A New Site Released - The Cocoa Cakery

Share |
by Rob 10. February 2011 08:52

I have just released a new site that I have built for my cousin. It’s a simple web shop to sell brownies for her company, The Cocoa Cakery. I had a box of brownies delivered last night and they are, quite simply, amazing. The smell as you open the box is worth the money in itself!

To try some for yourself head over to www.thecocoacakery.co.uk and get ordering!

Tags:

Share |

Running Loading and Completed JavaScript Functions Across Asynchronous PostBacks

Share |
by Rob 17. November 2010 14:38

I have just finished building a web app for work that worked with a few thousand rows of data in a gridview. I wanted to use ASP.NET AJAX and a loading image so that the end-user could know to wait while code was being executed. This bit isn’t too difficult, harder though was to show a message to the user using client-side scripting (JavaScript) that worked conditionally.

Executing some JavaScript whenever the page is loaded or even after every asynchronous postback isn’t much of a challenge, but to execute one conditionally takes a bit more thinking about. My first thought was to register a script block using ClientScriptManager.RegisterClientScriptBlock or ClientScriptManager.RegisterStartupScript, but neither of these functions can be undone – in other words the script cannot be removed from the page once it has been registered. Even if a new script block is registered using the same name, it won’t overwrite what has been written before but will just be discarded.

The way to get around this problem is to have a hidden field on the page, the value of which is updated on your asynchronous postback. Then write a JavaScript function that is executed after a postback has been completed, and in this function check the value of this hidden field and act on this value accordingly.

In this example I have used the MooTools JavaScript framework. This means I can make nice effects and improves the efficiency of my JavaScript coding, but MooTools is absolutely not a pre-requisite to solve this issue.

The solution can be downloaded by clicking here

The Code

Default.aspx

Inside the form tag we need our ScriptManager, UpdatePanel and save and cancel messages. To show our loading image we simply have to add an UpdateProgress section, and place our loading image inside the ProgressTemplate section.

In the UpdatePanel are our buttons to make a call to save or cancel (neither do anything on the back end, this is purely for illustration), and our hidden input field which will carry our switchable value.

<asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
</asp:ToolkitScriptManager>
    
<asp:UpdateProgress ID="updateProgress1" AssociatedUpdatePanelID="updatePnl" runat="server">
    <ProgressTemplate>
        <div id="progressBackgroundFilter"></div>
        <div id="processMessage"> Loading...<br /><br />
            <img alt="Loading" src="img/loader.gif" />
        </div>
    </ProgressTemplate>
</asp:UpdateProgress>

<div id="saveComplete" style="display:none;">
    <div id="progressBackgroundFilter"></div>
    <div id="processMessage"> Changes saved <br /><br />
        <img alt="Tick" src="img/tick.png" />
    </div>
</div>

<div id="cancelComplete" style="display:none;">
    <div id="progressBackgroundFilter"></div>
    <div id="processMessage"> Changes cancelled <br /><br />
        <img alt="Cross" src="img/cross.png" />
    </div>
</div>

<asp:UpdatePanel ID="updatePnl" runat="server">
    <ContentTemplate>
        <input id="hdnValue" type="hidden" runat="server" value="0" />
        <br /><br /><br /><br /><br />
        <asp:Button ID="BtnSubmit_Save" runat="server" Text="Save" 
            OnCommand="BtnSubmit_Command" CommandArgument="save" />
        <asp:Button ID="BtnSubmit_Cancel" runat="server" Text="Cancel" 
            OnCommand="BtnSubmit_Command" CommandArgument="cancel" />
    </ContentTemplate>
</asp:UpdatePanel>

 

Next step is to sort out the JavaScript that will execute when an asynchronous postback has completed. for this we need to add a function call to the end request handler of the page request manager. In the below example this is the line:

Sys.WebForms.PageRequestManager.getInstance().add_endRequest(ShowMessage);

All this means is that at the end of each request, the function ShowMessage() will be called.

I’m adding this to the domready event of the wondow using MooTools but you could just as easily run it in the body tags onload section. The ShowMessage() function will display a saved or cancelled message depending on which button was hit.

 

window.addEvent('domready', function () {
    $('saveComplete').setStyle('opacity', '0');
    $('saveComplete').setStyle('display', 'block');

    $('cancelComplete').setStyle('opacity', '0');
    $('cancelComplete').setStyle('display', 'block');

    Element.implement({
        fadeShow: function () { this.fade('in'); },
        fadeHide: function () { this.fade('out'); }
    });

    Sys.WebForms.PageRequestManager.getInstance().add_endRequest(ShowMessage);
});

function ShowMessage() {
    if ($('<%= hdnValue.ClientID %>').value == "save") {
        $('saveComplete').fadeShow();
        setTimeout("$('saveComplete').fadeHide()", 2000);
    } else {
        $('cancelComplete').fadeShow();
        setTimeout("$('cancelComplete').fadeHide()", 2000);
    }
}

 

Default.aspx.cs

The code behind doesn’t really do much at all. I’ve added a sleep instruction for 1.5 seconds only because the loading message would show and disappear too quickly to be seen otherwise. The only other thing that is done is to add the CommandArgument of the pressed button into the hdnValue fields Value attribute.

using System.Web.UI;
using System.Web.UI.WebControls;

namespace JavaScriptOnAsyncPostBack
{
    public partial class Default : Page
    {
        protected void BtnSubmit_Command(object sender, CommandEventArgs e)
        {
            System.Threading.Thread.Sleep(1500);

            hdnValue.Value = e.CommandArgument.ToString();
        }
    }
}

Tags:

Share |

Useful C# Image Upload Example

Share |
by Rob 21. September 2010 14:38

For one of the websites I have created I needed my users to be able to upload images to the server and create multiple versions of these images in different sizes. This is useful if you need thumbnail and full-size images, etc.

I’ll show you how I approached the problem and if you think you will find the code useful then you can download it here.

Requirements

  • Image dimensions should be in one place so they can be easily changed if necessary.
  • Uploader should only allow images of the types PNG, GIF and JPG.
  • If upload directory does not exist it should be created automatically.
  • Upload page should show currently uploaded images and update this list when new images are added or deleted.

The Code

To start with I created a simple wrapper for the image information I will want to store in a BusinessObject project called Media.

Media.cs

using System;

namespace BusinessObject
{
    public class Media
    {
        public Guid MediaId { get; set; }
        public string FolderName { get; set; }
        public string URL { get; set; }
    }
}

I then set up a GlobalConstants class in a Common project. This class contains constants that are used throughout the code. It is in this class that we define the different image dimensions for the images we want to create on a user upload.

GlobalConstants.cs

using System.Collections.Generic;
using System.Linq;

namespace Common
{
    public class GlobalConstants
    {
        public class Imaging
        {
            public const int ThumbnailDim = 100;
            public const int ProfileDim = 250;
            public const int StandardDim = 450;

            public const string SaveFolderName = "MyImages";
            public const string SaveFolderNameServerPath = "Storage\\" +  SaveFolderName;

            public static string ThumbnailUrlPrefix = GetImageUrlPrefix(ThumbnailDim);
            public static string ProfileUrlPrefix = GetImageUrlPrefix(ProfileDim);
            public static string StandardUrlPrefix = GetImageUrlPrefix(StandardDim);

            public static string ThumbnailServerUrlPrefix = 
                GetImageServerUrlPrefix(ThumbnailDim);
            public static string ProfileServerUrlPrefix = GetImageServerUrlPrefix(ProfileDim);
            public static string StandardServerUrlPrefix = 
                GetImageServerUrlPrefix(StandardDim);

            public static List<int> ImageDims = new List<int>
                                                    {
                                                        ThumbnailDim, 
                                                        ProfileDim, 
                                                        StandardDim
                                                    };

            public static List<string> ImageServerUrlPrefixes = 
                GetImageServerUrlPrefixes_List();
            public static List<string> ImageUrlPrefixes = GetImageUrlPrefixes_List();
        }

        private static string GetImageUrlPrefix(int dim)
        {
            return "/" + dim + "x" + dim + "_";
        }

        private static List<string> GetImageUrlPrefixes_List()
        {
            return Imaging.ImageDims.Select(GetImageUrlPrefix).ToList();
        }

        private static string GetImageServerUrlPrefix(int dim)
        {
            return "\\" + dim + "x" + dim + "_";
        }

        private static List<string> GetImageServerUrlPrefixes_List()
        {
            return Imaging.ImageDims.Select(GetImageServerUrlPrefix).ToList();
        }
    }
}

I have called the different Image dimensions ThumbnailDim, ProfileDim and StandardDim but you should pick a naming convention for each image dimension that makes sense to you. I have added some extra fields for ease of use (…UrlPrefix fields and …ServerUrlPrefix fields) which will need altering if any dimensions are added or deleted from the list. It is of course possible to not use these and simply reference the method they are implementing instead, but I find having them there useful.

The image uploader will keep the aspect ratio of the oroginal image and then resize it so it’s longest side is the same length as the image dimensions above. (So for example a 1000x500 original would allow us to create a 100x50, a 250x125 and a 450x225 images).

A prefix will be added to each uploaded image that is saved on the server so that each group of differently saved files can have the same filename. For example, a file named picture.jpg would be saved 3 times as 100x100_picture.jpg, 250x250_picture.jpg and 450x450_picture.jpg. This is great when using a database to reference the files on the server, as you can simply save a record on the database as picture.jpg, and then reference any sized instance of that picture by adding the appropriate prefix.

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" 
Inherits="ImageUploader.Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Test image uploader</title>
</head>
<body>
    <form id="form1" runat="server">
    <div id="uploadarea">
        <asp:Literal ID="uploadMsg" runat="server"></asp:Literal>
        <div id="Div1" runat="server">
            <input type="file" size="45" runat="server" id="FileUpload1" />
            <asp:Label ID="Label1" runat="server" />
        </div>
        <div id="Div2" runat="server">
            <input type="file" size="45" runat="server" id="FileUpload2" />
            <asp:Label ID="Label2" runat="server" />
        </div>
        <div id="Div3" runat="server">
            <input type="file" size="45" runat="server" id="FileUpload3" />
            <asp:Label ID="Label3" runat="server" />
        </div>
        <br />
        <span>
        
        <asp:Button ID="btnSubmit" runat="server" OnClick="btnSubmit_Click" 
            Text="Upload Images" /></span>
    </div>
    
    <p></p>
    <p></p>
    
    <asp:Repeater ID="PhotoRepeater" runat="server">
          <ItemTemplate>
              <div>
                <img src="/Storage/<%#DataBinder.Eval(Container.DataItem, "FolderName")%>
                /100x100_<%#DataBinder.Eval(Container.DataItem, "URL")%>" 
                    alt='<%#DataBinder.Eval(Container.DataItem, "URL")%>' />
                  <asp:LinkButton ID="DeleteImageBtn" runat="server" Text="Delete" 
                    CommandName="mediaId" OnCommand="DeleteImageBtn_Click" 
                    CommandArgument='<%#DataBinder.Eval(Container.DataItem, "MediaId")%>'>
                    </asp:LinkButton>
              </div>
          </ItemTemplate>
      </asp:Repeater>
    </form>
</body>
</html>

 

Default.aspx.cs

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using BusinessObject;
using Common;
using Image = System.Drawing.Image;

namespace ImageUploader
{
    public partial class Default : Page
    {
        public List<Media> ImageList = new List<Media>();

        /// <summary>
        /// Handles the Load event of the Page control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event 
        /// data.</param>
        protected void Page_Load(object sender, EventArgs e)
        {
            if (Page.IsPostBack) return;

            // on page load get any images that are in the test folder directory and bind 
            // them to the repeater.
            GetImagesCurrentlyInTestFolder();
        }

        /// <summary>
        /// Handles the Click event of the btnSubmit control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event 
        /// data.</param>
        protected void btnSubmit_Click(object sender, EventArgs e)
        {
            // gets an HttpFileCollection of all the files that have been uploaded
            var uploadFilCol = Request.Files;

            // so now we need to iterate through the list of files and deal with each one in 
            // turn
            for (var i = 0; i < uploadFilCol.Count; i++)
            {
                // chuck the current file in the loop in a variable called file
                var file = uploadFilCol[i];

                // call CheckFileIsAnImage to make sure some muppet hasn't tried to upload a 
                // txt file or something
                var msg = CheckFileIsAnImage(file);

                // if msg is empty we know our file is an ok image, if not we need to show a 
                // message to the user
                if (!string.IsNullOrEmpty(msg))
                    ShowMessage(msg, i);
                else
                {
                    // our file is ok. so now we get the filename of the file we are looking at
                    var fileName = Path.GetFileName(file.FileName);

                    // then we call CheckAndCreateDirectory which sees if the directory 
                    // structure we want to save to exists.
                    // if it doesn't exist it creates the directory for us.
                    // either way, the method will return the path to save the image to.
                    //
                    // this is where you would do some work on creating a custom folder root 
                    // if that's what you wanted (for example if you wanted another folder 
                    // within the storage system that was the artists name, or a gallery
                    // id, etc, etc.
                    var savePath = CheckAndCreateDirectory(
                           Server.MapPath(GlobalConstants.Imaging.SaveFolderNameServerPath));

                    // now we save the image to the server. in the process we allocate a new 
                    // filename (in this case a guid).
                    // you can use whatever you like here but remember all image names must 
                    // be unique.
                    var newFilename = SaveUploadedImageToServer(savePath, file);

                    // here is where you would save the newFilename to the db

                    // we've got this far so we can tell the user this file was saved ok
                    ShowMessage(" " + fileName + " uploaded successfully", i);
                }
            }

            // refresh the repeater with all images in the test folder
            GetImagesCurrentlyInTestFolder();
        }

        /// <summary>
        /// Checks the file is an image.
        /// </summary>
        /// <param name="file">The file.</param>
        /// <returns></returns>
        public static string CheckFileIsAnImage(HttpPostedFile file)
        {
            // if the file is null or has no content it's obviously a dirty wrongun
            if (file == null) return "file is invalid, upload must have failed";
            if (file.ContentLength == 0) return "no file specified";

            // get the filename extension (e.g .jpg, .gif, etc) from the filename
            var extension = Path.GetExtension(file.FileName).ToLower();

            // we're only supporting jpg, png and gif in this (you can support more if you 
            // like though)
            if (extension != ".jpg" && extension != ".gif" && extension != ".png")
                return "unsupported image type";

            // if we got this far the file looks good, so return an empty string (which 
            // means everything ok)
            return string.Empty;
        }

        /// <summary>
        /// Checks the directory exists and creates if not.
        /// </summary>
        /// <param name="directory">The directory.</param>
        /// <returns></returns>
        public static string CheckAndCreateDirectory(string directory)
        {
            if (!Directory.Exists(directory))
                Directory.CreateDirectory(directory);

            return directory;
        }

        /// <summary>
        /// Shows the file upload message.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="fileUploadPos">The file upload pos.</param>
        private void ShowMessage(string message, int fileUploadPos)
        {
            // show messages for each file being uploaded (3 files, so have to have a 
            // message for each)
            switch (fileUploadPos)
            {
                case 0:
                    Label1.Text = message;
                    break;
                case 1:
                    Label2.Text = message;
                    break;
                default:
                    Label3.Text = message;
                    break;
            }
        }

        /// <summary>
        /// Saves the uploaded image to the server.
        /// </summary>
        /// <param name="filePath">The file path.</param>
        /// <param name="file">The file.</param>
        /// <returns></returns>
        public string SaveUploadedImageToServer(String filePath, HttpPostedFile file)
        {
            // first thing to do is create a new filename root by using a guid and the 
            // current file extension.
            // i use the guid as the filename and as the unique media id in the database, 
            // but you don't have to do it this way
            var mediaId = Guid.NewGuid();
            var fileNameExtension = Path.GetExtension(file.FileName).ToLower();

            // now we iterate through our image dimensions list so we can create the image 
            // sizes we want from the image uploaded.
            // we are creating 3 images - 100x100, 250x250 and 450x450
            foreach (var imageDim in GlobalConstants.Imaging.ImageDims)
            {
                // get the file as an image
                var uploadedImage = Image.FromStream(file.InputStream);
                // create our new filename using the media id, file extension and image 
                // dimensions.
                var fileName = imageDim + "x" + imageDim + "_" + mediaId + fileNameExtension;
                // now get the full server path and add on the filename
                var fullSavePath = filePath + "\\" + fileName;
                // we need to get the right ImageFormat so we don't try to save a jpg as a 
                // png, etc...
                var imageType = GetImageType(fileNameExtension);

                // if the height and width of the uploaded image are less that the size we 
                // are aiming for (e.g we want 100x100, they uploaded 80x80), just save the 
                // image as is.
                if (uploadedImage.Height <= imageDim && uploadedImage.Width <= imageDim)
                {
                    // save the image
                    uploadedImage.Save(fullSavePath, imageType);
                    // then get rid of it from memory
                    uploadedImage.Dispose();
                }
                else
                {
                    var newWidth = imageDim;
                    var newHeight = imageDim;

                    // check the heigh and width ratio. if we are making a 100x100 image, 
                    // we may need to make it 70x100 or 100x70 depending
                    // whether the image is landscape or portrait
                    if (uploadedImage.Height > uploadedImage.Width)
                        newWidth = (Int32) Math.Ceiling(
                            ((double) uploadedImage.Width/uploadedImage.Height)*imageDim);
                    else
                        newHeight = (Int32) Math.Ceiling(
                            ((double) uploadedImage.Height/uploadedImage.Width)*imageDim);

                    // now write a new image out using the dimensions we've calculated
                    var smallerImg = new Bitmap(newWidth, newHeight);
                    var g = Graphics.FromImage(smallerImg);

                    // a few options, no need to worry about these
                    g.SmoothingMode = SmoothingMode.HighQuality;
                    g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    g.PixelOffsetMode = PixelOffsetMode.HighQuality;

                    foreach (var pItem in uploadedImage.PropertyItems)
                    {
                        smallerImg.SetPropertyItem(pItem);
                    }

                    // draw the image
                    g.DrawImage(uploadedImage, new Rectangle(0, 0, newWidth, newHeight));

                    // get rid of the uploaded image stream from memory
                    uploadedImage.Dispose();

                    // save the new file
                    smallerImg.Save(fullSavePath, imageType);

                    // get rid of the new file from memory
                    smallerImg.Dispose();
                }
            }

            // return the new filename
            return mediaId + fileNameExtension;
        }

        /// <summary>
        /// Gets the type of the image.
        /// </summary>
        /// <param name="fileExt">The file ext.</param>
        /// <returns></returns>
        private static ImageFormat GetImageType(string fileExt)
        {
            switch (fileExt)
            {
                case ".jpg":
                    return ImageFormat.Jpeg;
                case ".gif":
                    return ImageFormat.Gif;
                default: // (png)
                    return ImageFormat.Png;
            }
        }

        /// <summary>
        /// Handles the Click event of the DeleteImageBtn control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Web.UI.WebControls.CommandEventArgs"/> 
        /// instance containing the event data.</param>
        public void DeleteImageBtn_Click(Object sender, CommandEventArgs e)
        {
            DeleteImageFromDb(e);

            DeleteImageFromServer(e);

            GetImagesCurrentlyInTestFolder();
        }

        /// <summary>
        /// Deletes the image from server.
        /// </summary>
        /// <param name="e">The <see cref="System.Web.UI.WebControls.CommandEventArgs"/> 
        /// instance containing the event data.</param>
        private void DeleteImageFromServer(CommandEventArgs e)
        {
            DeleteImage(Server.MapPath(GlobalConstants.Imaging.SaveFolderNameServerPath), 
                e.CommandArgument.ToString());
        }

        /// <summary>
        /// Deletes the image.
        /// </summary>
        /// <param name="directoryPath">The directory path.</param>
        /// <param name="mediaId">The media id.</param>
        public static void DeleteImage(String directoryPath, String mediaId)
        {
            DeleteImagesInList(Directory.GetFiles(directoryPath, "*" + mediaId + "*"));
        }

        /// <summary>
        /// Deletes the images in list.
        /// </summary>
        /// <param name="imgList">The img list.</param>
        private static void DeleteImagesInList(IEnumerable<string> imgList)
        {
            foreach (var img in imgList)
            {
                var imgInfo = new FileInfo(img);
                imgInfo.Delete();
            }
        }

        /// <summary>
        /// Deletes the image from db.
        /// </summary>
        /// <param name="e">The <see cref="System.Web.UI.WebControls.CommandEventArgs"/> 
        /// instance containing the event data.</param>
        private void DeleteImageFromDb(CommandEventArgs e)
        {
            // here you would remove all references to the particular image in the db
        }

        /// <summary>
        /// Gets the images currently in test folder and bind to the photo repeater.
        /// </summary>
        private void GetImagesCurrentlyInTestFolder()
        {
            GetImages();

            PhotoRepeater.Dispose();
            PhotoRepeater.DataSource = ImageList;
            PhotoRepeater.DataBind();
        }

        /// <summary>
        /// Gets the images from the server location.
        /// </summary>
        public void GetImages()
        {
            // if the directory is there we'll have to create it or it'll fall over on the 
            // reference below
            var savePath = CheckAndCreateDirectory(
                Server.MapPath(GlobalConstants.Imaging.SaveFolderNameServerPath));

            // get all the files in the test directory
            var allFiles = Directory.GetFiles(savePath, "*");

            // for every file in the directory create a media object and add it to our list 
            // so we can bind it to the repeater
            foreach (var file in allFiles)
            {
                // get the filename
                var media = new Media {FolderName = GlobalConstants.Imaging.SaveFolderName};

                var splitterArrayToLoseAllFoldersInPath = file.Split(new[] {'\\'});
                var lastIndex = splitterArrayToLoseAllFoldersInPath.Length - 1;
                var getTheFileNameWhichIsTheLastItemInTheArray =
                    splitterArrayToLoseAllFoldersInPath[lastIndex];

                // we only want the thumbnail images
                if (!getTheFileNameWhichIsTheLastItemInTheArray.StartsWith(
                    GlobalConstants.Imaging.ThumbnailDim + "x" +
                    GlobalConstants.Imaging.ThumbnailDim)) 
                    continue;

                var filenameWithoutDimensions = 
                    getTheFileNameWhichIsTheLastItemInTheArray.Substring(8);

                media.URL = filenameWithoutDimensions;

                var splitterArrayToLoseFileExtension = 
                    filenameWithoutDimensions.Split(new[] {'.'});

                media.MediaId = new Guid(splitterArrayToLoseFileExtension[0]);

                ImageList.Add(media);
            }
        }
    }
}

The above is the code behind for our image uploader page. The code is heavily commented, so hopefully there shouldn’t be any problems understanding what it does. The code was adapted from the original code I wrote which saved the image details for all the uploaded images to a database. I have left a couple of references to the database in the code so you can understand where to implement this functionality when it is required. For now, the code has been adapted to just use the file system instead.

I’m not going to go through the code and explain it line by line, instead I would rather you downloaded the solution and have a play around with it. It should be self-explanatory – especially if you run through in debug mode.

Enjoy :o)

Tags:

Share |

Getting Started With The Vimeo API in C#

Share |
by Rob 6. August 2010 16:58

In my last post I showed you how to get started with using Google’s YouTube API to return a user’s favourites feed and get information for a single video. In this article I continue the theme by showing you how to use the Vimeo API to search and retrieve a collection of videos and then retrieve and show one video.

You can download the source files for this solution here. UPDATE: The solution is in VS2010, on request I have made a VS2005 version that can be downloaded here.

UPDATE: Please ensure you have the latest version of Flash player installed otherwise the videos might not show! (I just tried in Internet Explorer and had to update).

Vimeo is a great video repository and is home to lots of drifting videos. Because of the prevalence of drifting videos I wrote a wrapper for the Vimeo API in C# so I could use it on JDMLegion.com.

Before reading any further I suggest you have a look through Vimeo’s API guide’s, both simple and advanced, by visiting www.vimeo.com/api . If you are not familiar with OAuth or OEmbed, it would be worth having a quick skim through the following 2 pages as well - www.vimeo.com/api/docs/oauth and www.vimeo.com/api/docs/oembed.

The Vimeo API can output both JSON and XML, but I will be using only XML for this solution.

Vimeo Consumer Key And Consumer Secret

In order for OAuth requests to work for the advanced API you will need to register with Vimeo and obtain a consumer key and consumer secret – A little like the developer key we had to request from Google for the YouTube API to work in my previous post. You can get a consumer key and consumer secret at www.vimeo.com/api/applications/new.

The Code

As with my YouTube solution, I have separated this solution into 3 projects - the web application and 2 class libraries. There is some extra code in this solution in the VimeoAPI class that serves as interfaces for methods that the Vimeo API offers but we are not using in this example. Whilst these are untested and for this solution are not necessary, I have decided to add them to save you some work should you want to use any of these methods in the future.

We’ll start with our BusinessObject class library.

VideoExtracted.cs

namespace BusinessObject
{
    public class VideoExtracted
    {
        public string VideoId { get; set; }
        public string Title { get; set; }
        public string Thumbnail { get; set; }
        public string Description { get; set; }
    }
}

This is a wrapper for the video information we want returned from the Vimeo API.

OEmbed.cs

using System;
using System.Xml.Serialization;

namespace BusinessObject
{
    [SerializableAttribute]
    [XmlTypeAttribute(AnonymousType = true)]
    [XmlRootAttribute(Namespace = "", IsNullable = false, ElementName = "oembed")]
    public class OEmbed
    {
        public string type { get; set; }
        public string version { get; set; }
        public string provider_name { get; set; }
        public string provider_url { get; set; }
        public string title { get; set; }
        public string author_name { get; set; }
        public string author_url { get; set; }
        public string is_plus { get; set; }
        public string html { get; set; }
        public string width { get; set; }
        public string height { get; set; }
        public string duration { get; set; }
        public string thumbnail_url { get; set; }
        public string thumbnail_width { get; set; }
        public string thumbnail_height { get; set; }
        public string video_id { get; set; }
    }
}

This is a wrapper for our OEmbed request.

VimeoVideoWrapper.cs

using System;
using System.Xml.Serialization;

namespace BusinessObject
{
    [SerializableAttribute]
    [XmlRootAttribute(Namespace = "", IsNullable = false, ElementName = "videos")]
    public class VimeoVideoWrapper
    {
        [XmlElementAttribute("video")]
        public VimeoVideo[] Videos { get; set;}
    }

    [SerializableAttribute]
    public class VimeoVideo
    {
        public string id { get; set; }
        public string title { get; set; }
        public string description { get; set; }
        public string url { get; set; }
        public string upload_date { get; set; }
        public string thumbnail_small { get; set; }
        public string thumbnail_medium { get; set; }
        public string thumbnail_large { get; set; }
        public string user_name { get; set; }
        public string user_url { get; set; }
        public string user_portrait_small { get; set; }
        public string user_portrait_medium { get; set; }
        public string user_portrait_large { get; set; }
        public string user_portrait_huge { get; set; }
        public string stats_number_of_likes { get; set; }
        public string stats_number_of_plays { get; set; }
        public string stats_number_of_comments { get; set; }
        public string duration { get; set; }
        public string width { get; set; }
        public string height { get; set; }
        public string tags { get; set; }
    }
}

This is a wrapper for our Vimeo video request.

VimeoVideoThumbnailResponse.cs

using System;
using System.Xml.Serialization;

namespace BusinessObject
{
    [SerializableAttribute]
    [XmlTypeAttribute(AnonymousType = true)]
    [XmlRootAttribute(Namespace = "", IsNullable = false, ElementName = "rsp")]
    public class VimeoVideoThumbnailsResponse
    {
        [XmlElementAttribute("thumbnails", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public VimeoVideoThumbnailsWrapper thumbnails { get; set; }
        [XmlAttributeAttribute()]
        public string generated_in { get; set; }
        [XmlAttributeAttribute()]
        public string stat { get; set; }
    }

    [SerializableAttribute]
    [XmlTypeAttribute(AnonymousType = true)]
    public class VimeoVideoThumbnailsWrapper
    {
        [XmlElementAttribute("thumbnail", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public VimeoVideoThumbnailWrapper[] thumbnail { get; set; }
    }

    [SerializableAttribute]
    [XmlTypeAttribute(AnonymousType = true)]
    public class VimeoVideoThumbnailWrapper
    {
        [XmlAttributeAttribute()]
        public string height { get; set; }
        [XmlAttributeAttribute()]
        public string width { get; set; }
        [XmlText()]
        public string thumbnail { get; set; }
    }
}

A wrapper to use when requesting Vimeo video thumbnails.

VimeoSearchResponse.cs

using System;
using System.Xml.Serialization;

namespace BusinessObject
{
    [SerializableAttribute]
    [XmlTypeAttribute(AnonymousType = true)]
    [XmlRootAttribute(Namespace = "", IsNullable = false, ElementName = "rsp")]
    public partial class VimeoSearchResponse
    {
        [XmlElementAttribute("videos", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public SearchResponseVideosWrapper videos { get; set; }
        [XmlAttributeAttribute()]
        public string generated_in { get; set; }
        [XmlAttributeAttribute()]
        public string stat { get; set; }
    }

    [SerializableAttribute]
    [XmlTypeAttribute(AnonymousType = true)]
    public partial class SearchResponseVideosWrapper
    {
        [XmlElementAttribute("video", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public SearchResponseVideosWrapperVideo[] video { get; set; }
        [XmlAttributeAttribute()]
        public string on_this_page { get; set; }
        [XmlAttributeAttribute()]
        public string page { get; set; }
        [XmlAttributeAttribute()]
        public string perpage { get; set; }
        [XmlAttributeAttribute()]
        public string total { get; set; }
    }

    [SerializableAttribute]
    [XmlTypeAttribute(AnonymousType = true)]
    public partial class SearchResponseVideosWrapperVideo
    {
        [XmlAttributeAttribute()]
        public string embed_privacy { get; set; }
        [XmlAttributeAttribute()]
        public string id { get; set; }
        [XmlAttributeAttribute()]
        public string is_hd { get; set; }
        [XmlAttributeAttribute()]
        public string owner { get; set; }
        [XmlAttributeAttribute()]
        public string privacy { get; set; }
        [XmlAttributeAttribute()]
        public string title { get; set; }
        [XmlAttributeAttribute()]
        public string upload_date { get; set; }
    }

    [SerializableAttribute]
    [XmlTypeAttribute(AnonymousType = true)]
    [XmlRootAttribute(Namespace = "", IsNullable = false)]
    public partial class VimeoSearchResponses
    {
        [XmlElementAttribute("rsp")]
        public VimeoSearchResponse[] items { get; set; }
    }
}

A wrapper to use when making search requests.

VimeoErrorResponse.cs

using System;
using System.Xml.Serialization;

namespace BusinessObject
{
    [SerializableAttribute]
    [XmlTypeAttribute(AnonymousType = true)]
    [XmlRootAttribute(Namespace = "", IsNullable = false, ElementName = "rsp")]
    public class VimeoErrorResponse
    {
        [XmlElementAttribute("err", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public VimeoErrorWrapper error { get; set; }
        [XmlAttributeAttribute()]
        public string generated_in { get; set; }
        [XmlAttributeAttribute()]
        public string stat { get; set; }
    }

    [SerializableAttribute]
    [XmlTypeAttribute(AnonymousType = true)]
    public class VimeoErrorWrapper
    {
        [XmlAttributeAttribute()]
        public string code { get; set; }
        [XmlAttributeAttribute()]
        public string msg { get; set; }
    }
}

A wrapper for any error responses.

Now we need to create our Common class library. As in the YouTube project we have a GlobalConstants class.

GlobalConstants.cs

using System;
using System.Text;

namespace Common
{
    /// <summary>
    /// Global constants for the solution
    /// </summary>
    public class GlobalConstants
    {
        #region VimeoAPI
        /// <summary>
        /// Constants required to use the Vimeo API
        /// </summary>
        public class VimeoAPI
        {
            /// <summary>
            /// the vimeo api consumer key - your consumer key
            /// </summary>
            public const string ConsumerKey = "your consumer key";
            /// <summary>
            /// the vimeo api consumer secret - your consumer secret
            /// </summary>
            public const string ConsumerSecret = "your consumer secret";
            /// <summary>
            /// http://vimeo.com/api/rest/v2/
            /// </summary>
            public const string StandardAdvancedApiUrl = "http://vimeo.com/api/rest/v2";
            /// <summary>
            /// StandardAdvancedApiUrl + ?method=vimeo.videos.search&query=
            /// </summary>
            public const string SearchUrl = StandardAdvancedApiUrl 
                + "?method=vimeo.videos.search&per_page=15&query=";
            /// <summary>
            /// StandardAdvancedApiUrl + ?method=vimeo.videos.getThumbnailUrls&video_id=
            /// </summary>
            public const string GetVideoThumbnailsUrl = StandardAdvancedApiUrl 
                + "?method=vimeo.videos.getThumbnailUrls&video_id=";
            /// <summary>
            /// create all required Oauth parameters
            /// </summary>
            public static string OAuthParameters = BuildOAuthParameters();

            /// <summary>
            /// http://vimeo.com/api/oembed.xml?url=http%3A//vimeo.com/
            /// </summary>
            public const string OembedRequestUrlFormat = 
                "http://vimeo.com/api/oembed.xml?url=http%3A//vimeo.com/";
            /// <summary>
            /// http://vimeo.com/api/v2/
            /// </summary>
            /// <see cref="http://www.vimeo.com/api/docs/simple-api"/>
            public const string BaseVimeoUrl = "http://vimeo.com/api/v2/";
            /// <summary>
            /// http://vimeo.com/api/v2/username/request.output
            /// </summary>
            /// <see cref="http://www.vimeo.com/api/docs/simple-api"/>
            public const string UserRequestUrlFormat = BaseVimeoUrl + "{0}/{1}.{2}";
            /// <summary>
            /// http://vimeo.com/api/v2/video/video_id.output
            /// </summary>
            /// /// <see cref="http://www.vimeo.com/api/docs/simple-api"/>
            public const string VideoRequestUrlFormat = BaseVimeoUrl + "video/{0}.{1}";
            /// <summary>
            /// http://vimeo.com/api/v2/activity/username/request.output
            /// </summary>
            /// /// <see cref="http://www.vimeo.com/api/docs/simple-api"/>
            public const string ActivityRequestUrlFormat = BaseVimeoUrl 
                + "activity/{0}/{1}.{2}";
            /// <summary>
            /// http://vimeo.com/api/v2/group/groupname/request.output
            /// </summary>
            /// /// <see cref="http://www.vimeo.com/api/docs/simple-api"/>
            public const string GroupRequestUrlFormat = BaseVimeoUrl + "group/{0}/{1}.{2}";
            /// <summary>
            /// http://vimeo.com/api/v2/channel/channelname/request.output
            /// </summary>
            /// /// <see cref="http://www.vimeo.com/api/docs/simple-api"/>
            public const string ChannelRequestUrlFormat = BaseVimeoUrl 
                + "channel/{0}/{1}.{2}";
            /// <summary>
            /// http://vimeo.com/api/v2/album/album_id/request.output
            /// </summary>
            /// /// <see cref="http://www.vimeo.com/api/docs/simple-api"/>
            public const string AlbumRequestUrlFormat = BaseVimeoUrl + "album/{0}/{1}.{2}";
            /// <summary>
            /// Vimeo player width
            /// </summary>
            public const string VimeoPlayerWidth = "550";
            /// <summary>
            /// Vimeo player height
            /// </summary>
            public const string VimeoPlayerHeight = "425";

            /// <summary>
            /// Builds the Oauth parameters.
            /// </summary>
            /// <returns></returns>
            protected static string BuildOAuthParameters()
            {
                var sb = new StringBuilder();

                sb.Append("&oauth_consumer_key=");
                sb.Append(ConsumerKey);
                sb.Append("&oauth_nonce=");
                sb.Append(Guid.NewGuid());
                sb.Append("&oauth_signature_method=HMAC-SHA1");
                sb.Append("&oauth_timestamp=");

                TimeSpan ts = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0));

                sb.Append(ts.TotalSeconds);
                sb.Append("&oauth_version=1.0");

                return sb.ToString();
            }
        }
        #endregion

        #region Links
        /// <summary>
        /// Page links
        /// </summary>
        public class Links
        {
            /// <summary>
            /// Default.aspx
            /// </summary>
            public const string Default = "/Default.aspx";
            /// <summary>
            /// ViewVideo.aspx?vid=
            /// </summary>
            public const string ViewVideo = "/ViewVideo.aspx?" + Querystring.Video + "=";
        }
        #endregion

        #region Querystring
        /// <summary>
        /// Querystring identifiers
        /// </summary>
        public class Querystring
        {
            /// <summary>
            /// vid
            /// </summary>
            public const string Video = "vid";
        }
        #endregion

        #region ErrorMessages
        /// <summary>
        /// Querystring identifiers
        /// </summary>
        public class ErrorMessages
        {
            /// <summary>
            /// Sorry, Vimeo's search service is temporarily unavailable. 
            /// Please try again in a few minutes.
            /// </summary>
            public const string SearchServiceUnavailable 
                = "Sorry, Vimeo's search service is temporarily unavailable. "
                +"Please try again in a few minutes.";
            /// <summary>
            /// Sorry, there was an error with your search. If the problem persists please #
            /// contact us and let us know about the issue, thanks.
            /// </summary>
            public const string SearchError 
                = "Sorry, there was an error with your search. If the problem persists please"
                + " contact us and let us know about the issue, thanks.";
            /// <summary>
            /// Sorry, your query returned no results
            /// </summary>
            public const string NoSearchResults = "Sorry, your query returned no results";
        }
        #endregion
    }
}

 

You will need to change the consumer key and consumer secrets field in this class to the ones you received when you signed up to Vimeo and registered your application.

OAuthBase.cs

using System;
using System.Security.Cryptography;
using System.Collections.Generic;
using System.Text;
using System.Web;
using BusinessObject.Enums;

namespace Common
{
    public class OAuthBase
    {
        /// <summary>
        /// Provides an internal structure to sort the query parameter
        /// </summary>
        protected class QueryParameter
        {
            public QueryParameter(string name, string value)
            {
                Name = name;
                Value = value;
            }

            public string Name { get; private set; }
            public string Value { get; private set; }
        }

        /// <summary>
        /// Comparer class used to perform the sorting of the query parameters
        /// </summary>
        protected class QueryParameterComparer : IComparer<QueryParameter>
        {
            public int Compare(QueryParameter x, QueryParameter y)
            {
                return x.Name == y.Name 
                    ? string.Compare(x.Value, y.Value) 
                    : string.Compare(x.Name, y.Name);
            }
        }

        protected const string OAuthVersion = "1.0";
        protected const string OAuthParameterPrefix = "oauth_";

        // List of know and used oauth parameters' names
        protected const string OAuthConsumerKeyKey = "oauth_consumer_key";
        protected const string OAuthCallbackKey = "oauth_callback";
        protected const string OAuthVersionKey = "oauth_version";
        protected const string OAuthSignatureMethodKey = "oauth_signature_method";
        protected const string OAuthSignatureKey = "oauth_signature";
        protected const string OAuthTimestampKey = "oauth_timestamp";
        protected const string OAuthNonceKey = "oauth_nonce";
        protected const string OAuthTokenKey = "oauth_token";
        protected const string OAuthTokenSecretKey = "oauth_token_secret";

        protected const string HMACSHA1SignatureType = "HMAC-SHA1";
        protected const string PlainTextSignatureType = "PLAINTEXT";
        protected const string RSASHA1SignatureType = "RSA-SHA1";

        protected Random random = new Random();

        protected string unreservedChars = 
            "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";

        /// <summary>
        /// Helper function to compute a hash value
        /// </summary>
        /// <param name="hashAlgorithm">The hashing algoirhtm used. If that algorithm needs 
        /// some initialization, like HMAC and its derivatives, they should be initialized 
        /// prior to passing it to this function</param>
        /// <param name="data">The data to hash</param>
        /// <returns>a Base64 string of the hash value</returns>
        private static string ComputeHash(HashAlgorithm hashAlgorithm, string data)
        {
            if (hashAlgorithm == null)
                throw new ArgumentNullException("hashAlgorithm");

            if (string.IsNullOrEmpty(data))
                throw new ArgumentNullException("data");

            byte[] dataBuffer = Encoding.ASCII.GetBytes(data);
            byte[] hashBytes = hashAlgorithm.ComputeHash(dataBuffer);

            return Convert.ToBase64String(hashBytes);
        }

        /// <summary>
        /// Internal function to cut out all non oauth query string parameters 
        /// (all parameters not begining with "oauth_")
        /// </summary>
        /// <param name="parameters">The query string part of the Url</param>
        /// <returns>A list of QueryParameter each containing the parameter name and 
        /// value</returns>
        private static List<QueryParameter> GetQueryParameters(string parameters)
        {
            if (parameters.StartsWith("?"))
                parameters = parameters.Remove(0, 1);

            var result = new List<QueryParameter>();

            if (!string.IsNullOrEmpty(parameters))
            {
                string[] p = parameters.Split('&');
                foreach (string s in p)
                {
                    if (string.IsNullOrEmpty(s) || s.StartsWith(OAuthParameterPrefix)) 
                        continue;

                    if (s.IndexOf('=') > -1)
                    {
                        string[] temp = s.Split('=');
                        result.Add(new QueryParameter(temp[0], temp[1]));
                    }
                    else
                        result.Add(new QueryParameter(s, string.Empty));
                }
            }

            return result;
        }

        /// <summary>
        /// This is a different Url Encode implementation since the default 
        /// .NET one outputs the percent encoding in lower case.
        /// While this is not a problem with the percent encoding spec, 
        /// it is used in upper case throughout OAuth
        /// </summary>
        /// <param name="value">The value to Url encode</param>
        /// <returns>Returns a Url encoded string</returns>
        protected string UrlEncode(string value)
        {
            var result = new StringBuilder();

            foreach (char symbol in value)
            {
                if (unreservedChars.IndexOf(symbol) != -1)
                    result.Append(symbol);
                else
                    result.Append('%' + String.Format("{0:X2}", (int)symbol));
            }

            return result.ToString();
        }

        /// <summary>
        /// Normalizes the request parameters according to the spec
        /// </summary>
        /// <param name="parameters">The list of parameters already sorted</param>
        /// <returns>a string representing the normalized parameters</returns>
        protected string NormalizeRequestParameters(IList<QueryParameter> parameters)
        {
            var sb = new StringBuilder();
            QueryParameter p;
            for (int i = 0; i < parameters.Count; i++)
            {
                p = parameters[i];
                sb.AppendFormat("{0}={1}", p.Name, p.Value);

                if (i < parameters.Count - 1)
                    sb.Append("&");
            }

            return sb.ToString();
        }

        /// <summary>
        /// Generate the signature base that is used to produce the signature
        /// </summary>
        /// <param name="url">The full url that needs to be signed including 
        /// its non OAuth url parameters</param>
        /// <param name="consumerKey">The consumer key</param>        
        /// <param name="token">The token, if available. If not available 
        /// pass null or an empty string</param>
        /// <param name="tokenSecret">The token secret, if available. If not 
        /// available pass null or an empty string</param>
        /// <param name="httpMethod">The http method used. Must be a valid HTTP 
        /// method verb (POST,GET,PUT, etc)</param>
        /// <param name="signatureType">The signature type. To use the default 
        /// values use <see cref="OAuthBase.OAuthSignatureType">
        /// OAuthBase.OAuthSignatureType</see>.
        /// </param>
        /// <returns>The signature base</returns>
        public string GenerateSignatureBase(Uri url, string consumerKey, string token, 
            string tokenSecret, string httpMethod, string timeStamp, string nonce, 
            string signatureType, out string normalizedUrl, 
            out string normalizedRequestParameters)
        {
            if (token == null)
                token = string.Empty;

            //if (tokenSecret == null)
            //    tokenSecret = string.Empty;

            if (string.IsNullOrEmpty(consumerKey))
                throw new ArgumentNullException("consumerKey");

            if (string.IsNullOrEmpty(httpMethod))
                throw new ArgumentNullException("httpMethod");

            if (string.IsNullOrEmpty(signatureType))
                throw new ArgumentNullException("signatureType");

            normalizedUrl = null;
            normalizedRequestParameters = null;

            List<QueryParameter> parameters = GetQueryParameters(url.Query);
            parameters.Add(new QueryParameter(OAuthVersionKey, OAuthVersion));
            parameters.Add(new QueryParameter(OAuthNonceKey, nonce));
            parameters.Add(new QueryParameter(OAuthTimestampKey, timeStamp));
            parameters.Add(new QueryParameter(OAuthSignatureMethodKey, signatureType));
            parameters.Add(new QueryParameter(OAuthConsumerKeyKey, consumerKey));

            if (!string.IsNullOrEmpty(token))
                parameters.Add(new QueryParameter(OAuthTokenKey, token));

            parameters.Sort(new QueryParameterComparer());

            normalizedUrl = string.Format("{0}://{1}", url.Scheme, url.Host);

            if (!((url.Scheme == "http" && url.Port == 80) || 
                (url.Scheme == "https" && url.Port == 443)))
                normalizedUrl += ":" + url.Port;

            normalizedUrl += url.AbsolutePath;
            normalizedRequestParameters = NormalizeRequestParameters(parameters);

            var signatureBase = new StringBuilder();
            signatureBase.AppendFormat("{0}&", httpMethod.ToUpper());
            signatureBase.AppendFormat("{0}&", UrlEncode(normalizedUrl));
            signatureBase.AppendFormat("{0}", UrlEncode(normalizedRequestParameters));

            return signatureBase.ToString();
        }

        /// <summary>
        /// Generate the signature value based on the given signature base
        /// and hash algorithm
        /// </summary>
        /// <param name="signatureBase">The signature based as produced 
        /// by the GenerateSignatureBase method or by any other means</param>
        /// <param name="hash">The hash algorithm used to perform the hashing. 
        /// If the hashing algorithm requires initialization or a key it 
        /// should be set prior to calling this method</param>
        /// <returns>A base64 string of the hash value</returns>
        public string GenerateSignatureUsingHash(string signatureBase, HashAlgorithm hash)
        {
            return ComputeHash(hash, signatureBase);
        }

        /// <summary>
        /// Generates a signature using the HMAC-SHA1 algorithm
        /// </summary>        
        /// <param name="url">The full url that needs to be signed including its 
        /// non OAuth url parameters</param>
        /// <param name="consumerKey">The consumer key</param>
        /// <param name="consumerSecret">The consumer seceret</param>
        /// <param name="token">The token, if available. If not available pass 
        /// null or an empty string</param>
        /// <param name="tokenSecret">The token secret, if available. If not 
        /// available pass null or an empty string</param>
        /// <param name="httpMethod">The http method used. Must be a valid HTTP 
        /// method verb (POST,GET,PUT, etc)</param>
        /// <returns>A base64 string of the hash value</returns>
        public string GenerateSignature(Uri url, string consumerKey, string consumerSecret, 
            string token, string tokenSecret, string httpMethod, string timeStamp, 
            string nonce, out string normalizedUrl, out string normalizedRequestParameters)
        {
            return GenerateSignature(url, consumerKey, consumerSecret, token, tokenSecret, 
                httpMethod, timeStamp, nonce, OAuthSignatureType.HMACSHA1, out normalizedUrl, 
                out normalizedRequestParameters);
        }

        /// <summary>
        /// Generates a signature using the specified signatureType 
        /// </summary>        
        /// <param name="url">The full url that needs to be signed including 
        /// its non OAuth url parameters</param>
        /// <param name="consumerKey">The consumer key</param>
        /// <param name="consumerSecret">The consumer seceret</param>
        /// <param name="token">The token, if available. If not available pass 
        /// null or an empty string</param>
        /// <param name="tokenSecret">The token secret, if available. If not 
        /// available pass null or an empty string</param>
        /// <param name="httpMethod">The http method used. Must be a valid HTTP 
        /// method verb (POST,GET,PUT, etc)</param>
        /// <param name="signatureType">The type of signature to use</param>
        /// <returns>A base64 string of the hash value</returns>
        public string GenerateSignature(Uri url, string consumerKey, string consumerSecret, 
            string token, string tokenSecret, string httpMethod, string timeStamp, 
            string nonce, OAuthSignatureType signatureType, out string normalizedUrl, 
            out string normalizedRequestParameters)
        {
            normalizedUrl = null;
            normalizedRequestParameters = null;

            switch (signatureType)
            {
                case OAuthSignatureType.PLAINTEXT:
                    return HttpUtility.UrlEncode(
                        string.Format("{0}&{1}", consumerSecret, tokenSecret));
                case OAuthSignatureType.HMACSHA1:
                    string signatureBase = GenerateSignatureBase(url, consumerKey, 
                        token, tokenSecret, 
                        httpMethod, timeStamp, nonce, HMACSHA1SignatureType,
                        out normalizedUrl, out normalizedRequestParameters);

                    var hmacsha1 = new HMACSHA1
                                       {
                                           Key = Encoding.ASCII.GetBytes(
                                                string.Format("{0}&{1}", 
                                                UrlEncode(consumerSecret),
                                                string.IsNullOrEmpty(tokenSecret) 
                                                    ? "" 
                                                    : UrlEncode(tokenSecret)))
                                       };

                    return GenerateSignatureUsingHash(signatureBase, hmacsha1);
                case OAuthSignatureType.RSASHA1:
                    throw new NotImplementedException();
                default:
                    throw new ArgumentException("Unknown signature type", "signatureType");
            }
        }

        /// <summary>
        /// Generate the timestamp for the signature        
        /// </summary>
        /// <returns></returns>
        public virtual string GenerateTimeStamp()
        {
            // Default implementation of UNIX time of the current UTC time
            TimeSpan ts = DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, 0));
            string timeStamp = ts.TotalSeconds.ToString();
            timeStamp = timeStamp.Substring(0, timeStamp.IndexOf("."));
            return timeStamp;
        }

        /// <summary>
        /// Generate a nonce (childish giggle)
        /// </summary>
        /// <returns></returns>
        public virtual string GenerateNonce()
        {
            // Just a simple implementation of a random number between 123400 and 9999999
            return random.Next(123400, 9999999).ToString();
        }
    }
}

 

This class contains all the methods required for making requests with OAuth.

VimeoAPI.cs

using System;
using System.IO;
using System.Net;
using System.Text;
using System.Web;
using System.Xml;
using System.Xml.Serialization;
using BusinessObject;
using BusinessObject.Enums;

namespace Common
{
    public class VimeoAPI
    {
        /// <summary>
        /// Executes an HTTP GET command and retrieves the vimeoApiOutputFormatType.        
        /// </summary>
        /// <param name="url">The URL to perform the GET operation</param>
        /// <param name="userName">The username to use with the request</param>
        /// <param name="password">The password to use with the request</param>
        /// <returns>The response of the request, or null if we got 404 or nothing.</returns>
        protected static string ExecuteGetCommand(string url, string userName, 
            string password)
        {
            using (var wc = new WebClient())
            {
                if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(password))
                    wc.Credentials = new NetworkCredential(userName, password);

                try
                {
                    using (Stream stream = wc.OpenRead(url))
                    {
                        using (var reader = new StreamReader(stream))
                        {
                            return reader.ReadToEnd();
                        }
                    }
                }
                catch (WebException ex)
                {
                    // Handle HTTP 404 errors gracefully and return a null string 
                    // to indicate there is no content.
                    if (ex.Response is HttpWebResponse)
                        if ((ex.Response as HttpWebResponse).StatusCode 
                            == HttpStatusCode.NotFound)
                            return null;

                    throw;
                }
            }
        }

        /// <summary>
        /// Builds the OAuth API request URL.
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <returns></returns>
        protected static string BuildOAuthApiRequestUrl(string url)
        {
            var oAuth = new OAuthBase();
            string nonce = oAuth.GenerateNonce();
            string timeStamp = oAuth.GenerateTimeStamp();

            string normalizedUrl;
            string normalizedRequestParameters;

            var uri = new Uri(url);

            string sig = oAuth.GenerateSignature(uri, GlobalConstants.VimeoAPI.ConsumerKey, 
                    GlobalConstants.VimeoAPI.ConsumerSecret, 
                    string.Empty, string.Empty, "GET", timeStamp, nonce, 
                    OAuthSignatureType.HMACSHA1, 
                    out normalizedUrl, out normalizedRequestParameters);
            
            sig = HttpUtility.UrlEncode(sig);

            var sb = new StringBuilder(uri.ToString());
            sb.AppendFormat("&oauth_consumer_key={0}&", GlobalConstants.VimeoAPI.ConsumerKey);
            sb.AppendFormat("oauth_nonce={0}&", nonce);
            sb.AppendFormat("oauth_timestamp={0}&", timeStamp);
            sb.AppendFormat("oauth_signature_method={0}&", "HMAC-SHA1");
            sb.AppendFormat("oauth_version={0}&", "1.0");
            sb.AppendFormat("oauth_signature={0}", sig);
            
            return sb.ToString();
        }

        /// <summary>
        /// XML requests
        /// </summary>
        public class RequestInXML
        {
            /// <summary>
            /// User requests
            /// </summary>
            public class User
            {
                /// <summary>
                /// Gets the albums user has created.
                /// </summary>
                /// <returns></returns>
                public static XmlDocument GetAlbumsUserHasCreated(string username)
                {
                    return DoUserRequestAsXML(VimeoApiUserRequestType.albums, username);
                }

                /// <summary>
                /// Gets the videos user has appeared in and created.
                /// </summary>
                /// <returns></returns>
                public static XmlDocument GetVideosUserHasAppearedInAndCreated
                    (string username)
                {
                    return DoUserRequestAsXML(VimeoApiUserRequestType.all_videos, username);
                }

                /// <summary>
                /// Gets the videos user has appeared in.
                /// </summary>
                /// <returns></returns>
                public static XmlDocument GetVideosUserHasAppearedIn(string username)
                {
                    return DoUserRequestAsXML(VimeoApiUserRequestType.appears_in, username);
                }

                /// <summary>
                /// Gets the channels user has created and is subscribed to.
                /// </summary>
                /// <returns></returns>
                public static XmlDocument GetChannelsUserHasCreatedAndIsSubscribedTo
                    (string username)
                {
                    return DoUserRequestAsXML(VimeoApiUserRequestType.channels, username);
                }

                /// <summary>
                /// Gets the videos users contacts like.
                /// </summary>
                /// <returns></returns>
                public static XmlDocument GetVideosUsersContactsLike(string username)
                {
                    return DoUserRequestAsXML(VimeoApiUserRequestType.contacts_like, username);
                }

                /// <summary>
                /// Gets the videos users contacts created.
                /// </summary>
                /// <returns></returns>
                public static XmlDocument GetVideosUsersContactsCreated(string username)
                {
                    return DoUserRequestAsXML(VimeoApiUserRequestType.contacts_videos, 
                        username);
                }

                /// <summary>
                /// Gets the groups user has created and joined.
                /// </summary>
                /// <returns></returns>
                public static XmlDocument GetGroupsUserHasCreatedAndJoined(string username)
                {
                    return DoUserRequestAsXML(VimeoApiUserRequestType.groups, username);
                }

                /// <summary>
                /// Gets the user info.
                /// </summary>
                /// <returns></returns>
                public static XmlDocument GetUserInfo(string username)
                {
                    return DoUserRequestAsXML(VimeoApiUserRequestType.info, username);
                }

                /// <summary>
                /// Gets the videos user likes.
                /// </summary>
                /// <returns></returns>
                public static XmlDocument GetVideosUserLikes(string username)
                {
                    return DoUserRequestAsXML(VimeoApiUserRequestType.likes, username);
                }

                /// <summary>
                /// Gets the videos user is subscribed to.
                /// </summary>
                /// <returns></returns>
                public static XmlDocument GetVideosUserIsSubscribedTo(string username)
                {
                    return DoUserRequestAsXML(VimeoApiUserRequestType.subscriptions, username);
                }

                /// <summary>
                /// Gets the videos created by user.
                /// </summary>
                /// <returns></returns>
                public static XmlDocument GetVideosCreatedByUser(string username)
                {
                    return DoUserRequestAsXML(VimeoApiUserRequestType.videos, username);
                }
            }

            /// <summary>
            /// Video requests
            /// </summary>
            public class Video
            {
                /// <summary>
                /// Gets the video.
                /// </summary>
                /// <param name="videoId">The video id.</param>
                /// <returns></returns>
                public static XmlDocument GetVideo(string videoId)
                {
                    return DoVideoRequestAsXML(videoId);
                }
            }

            /// <summary>
            /// Activity requests
            /// </summary>
            public class Activity
            {
                /// <summary>
                /// Gets the activity by the users contacts.
                /// </summary>
                /// <returns></returns>
                public static XmlDocument GetActivityByTheUsersContacts(string username)
                {
                    return DoActivityRequestAsXML(VimeoApiActivityRequestType.contacts_did, 
                        username);
                }

                /// <summary>
                /// Gets the activity by everyone.
                /// </summary>
                /// <returns></returns>
                public static XmlDocument GetActivityByEveryone(string username)
                {
                    return DoActivityRequestAsXML(VimeoApiActivityRequestType.everyone_did, 
                        username);
                }

                /// <summary>
                /// Gets the activity on the users contacts.
                /// </summary>
                /// <returns></returns>
                public static XmlDocument GetActivityOnTheUsersContacts(string username)
                {
                    return DoActivityRequestAsXML(VimeoApiActivityRequestType.happened_to_contacts, username);
                }

                /// <summary>
                /// Gets the activity on the user.
                /// </summary>
                /// <returns></returns>
                public static XmlDocument GetActivityOnTheUser(string username)
                {
                    return DoActivityRequestAsXML
                        (VimeoApiActivityRequestType.happened_to_user, username);
                }

                /// <summary>
                /// Gets the activity by the user.
                /// </summary>
                /// <returns></returns>
                public static XmlDocument GetActivityByTheUser(string username)
                {
                    return DoActivityRequestAsXML
                        (VimeoApiActivityRequestType.user_did, username);
                }
            }

            /// <summary>
            /// Album requests
            /// </summary>
            public class Album
            {
                /// <summary>
                /// Gets the album info.
                /// </summary>
                /// <param name="albumId">The album id.</param>
                /// <returns></returns>
                public static XmlDocument GetAlbumInfo(string albumId)
                {
                    return DoAlbumRequestAsXML(VimeoApiAlbumRequestType.info, albumId);
                }

                /// <summary>
                /// Gets the videos in album.
                /// </summary>
                /// <param name="albumId">The album id.</param>
                /// <returns></returns>
                public static XmlDocument GetVideosInAlbum(string albumId)
                {
                    return DoAlbumRequestAsXML(VimeoApiAlbumRequestType.videos, albumId);
                }
            }

            /// <summary>
            /// Channel requests
            /// </summary>
            public class Channel
            {
                /// <summary>
                /// Gets the channel info.
                /// </summary>
                /// <param name="channelName">Name of the channel.</param>
                /// <returns></returns>
                public static XmlDocument GetChannelInfo(string channelName)
                {
                    return DoChannelRequestAsXML(VimeoApiChannelRequestType.info, 
                        channelName);
                }

                /// <summary>
                /// Gets the videos in channel.
                /// </summary>
                /// <param name="channelName">Name of the channel.</param>
                /// <returns></returns>
                public static XmlDocument GetVideosInChannel(string channelName)
                {
                    return DoChannelRequestAsXML(VimeoApiChannelRequestType.videos, 
                        channelName);
                }
            }

            /// <summary>
            /// Group requests
            /// </summary>
            public class Group
            {
                /// <summary>
                /// Gets the group info.
                /// </summary>
                /// <param name="groupName">Name of the group.</param>
                /// <returns></returns>
                public static XmlDocument GetGroupInfo(string groupName)
                {
                    return DoGroupRequestAsXML(VimeoApiGroupRequestType.info, groupName);
                }

                /// <summary>
                /// Gets the users in group.
                /// </summary>
                /// <param name="groupName">Name of the group.</param>
                /// <returns></returns>
                public static XmlDocument GetUsersInGroup(string groupName)
                {
                    return DoGroupRequestAsXML(VimeoApiGroupRequestType.users, groupName);
                }

                /// <summary>
                /// Gets the videos in group.
                /// </summary>
                /// <param name="groupName">Name of the group.</param>
                /// <returns></returns>
                public static XmlDocument GetVideosInGroup(string groupName)
                {
                    return DoGroupRequestAsXML(VimeoApiGroupRequestType.videos, groupName);
                }
            }
        }

        #region Methods to perform the requests for each Vimeo request type
        /// <summary>
        /// Does the user request.
        /// </summary>
        /// <param name="vimeoApiOutputFormatType">Type of the vimeo API output format.</param>
        /// <param name="vimeoApiUserRequestType">Type of the vimeo API user request.</param>
        /// <param name="username">The username.</param>
        /// <returns></returns>
        protected static string DoUserRequest
            (VimeoApiOutputFormatType vimeoApiOutputFormatType, 
            VimeoApiUserRequestType vimeoApiUserRequestType, string username)
        {
            string url = string.Format(GlobalConstants.VimeoAPI.UserRequestUrlFormat, 
                username, GetVimeoApiUserRequestTypeString(vimeoApiUserRequestType), 
                GetVimeoApiOutputFormatTypeString(vimeoApiOutputFormatType));
            return ExecuteGetCommand(url, null, null);
        }

        /// <summary>
        /// Does the user request as XML.
        /// </summary>
        /// <param name="vimeoApiUserRequestType">Type of the vimeo API user request.</param>
        /// <param name="username">The username.</param>
        /// <returns></returns>
        protected static XmlDocument DoUserRequestAsXML
            (VimeoApiUserRequestType vimeoApiUserRequestType, string username)
        {
            string output = DoUserRequest(VimeoApiOutputFormatType.XML, 
                vimeoApiUserRequestType, username);
            if (!string.IsNullOrEmpty(output))
            {
                var xmlDocument = new XmlDocument();
                xmlDocument.LoadXml(output);

                return xmlDocument;
            }

            return null;
        }

        /// <summary>
        /// Does the video request.
        /// </summary>
        /// <param name="vimeoApiOutputFormatType">Type of the vimeo API output format.</param>
        /// <param name="videoId">The video id.</param>
        /// <returns></returns>
        protected static string DoVideoRequest
            (VimeoApiOutputFormatType vimeoApiOutputFormatType, string videoId)
        {
            string url = string.Format(GlobalConstants.VimeoAPI.VideoRequestUrlFormat, 
                videoId, 
                GetVimeoApiOutputFormatTypeString(vimeoApiOutputFormatType));
            return ExecuteGetCommand(url, null, null);
        }

        /// <summary>
        /// Does the video request as XML.
        /// </summary>
        /// <param name="videoId">The video id.</param>
        /// <returns></returns>
        protected static XmlDocument DoVideoRequestAsXML(string videoId)
        {
            string output = DoVideoRequest(VimeoApiOutputFormatType.XML, videoId);
            if (!string.IsNullOrEmpty(output))
            {
                var xmlDocument = new XmlDocument();
                xmlDocument.LoadXml(output);

                return xmlDocument;
            }

            return null;
        }

        /// <summary>
        /// Does the oembed request.
        /// </summary>
        /// <param name="vimeoApiOutputFormatType">Type of the vimeo API output format.</param>
        /// <param name="videoId">The video id.</param>
        /// <returns></returns>
        protected static string DoOembedRequest
            (VimeoApiOutputFormatType vimeoApiOutputFormatType, string videoId)
        {
            string url = GlobalConstants.VimeoAPI.OembedRequestUrlFormat + videoId
                         + "?maxwidth=" + GlobalConstants.VimeoAPI.VimeoPlayerWidth
                         + "&maxheight=" + GlobalConstants.VimeoAPI.VimeoPlayerHeight;

            return ExecuteGetCommand(url, null, null);
        }

        /// <summary>
        /// Does the oembed request as XML.
        /// </summary>
        /// <param name="videoId">The video id.</param>
        /// <returns></returns>
        protected static XmlDocument DoOembedRequestAsXML(string videoId)
        {
            string output = DoOembedRequest(VimeoApiOutputFormatType.XML, videoId);
            if (!string.IsNullOrEmpty(output))
            {
                var xmlDocument = new XmlDocument();
                xmlDocument.LoadXml(output);

                return xmlDocument;
            }

            return null;
        }

        /// <summary>
        /// Does a search request.
        /// </summary>
        /// <param name="query">The query.</param>
        /// <returns>XmlDocument</returns>
        protected static XmlDocument DoSearchRequest(string query)
        {
            string output = ExecuteGetCommand
                (BuildOAuthApiRequestUrl(GlobalConstants.VimeoAPI.SearchUrl + query), 
                null, null);

            if (!string.IsNullOrEmpty(output))
            {
                var xmlDocument = new XmlDocument();
                xmlDocument.LoadXml(output);

                return xmlDocument;
            }

            return null;
        }

        /// <summary>
        /// Does a get video thumbnails request.
        /// </summary>
        /// <param name="videoId">The video id.</param>
        /// <returns></returns>
        protected static XmlDocument DoGetVideoThumbnailsRequest(string videoId)
        {
            string output = ExecuteGetCommand
                (BuildOAuthApiRequestUrl(GlobalConstants.VimeoAPI.GetVideoThumbnailsUrl + videoId), 
                null, null);

            if (!string.IsNullOrEmpty(output))
            {
                var xmlDocument = new XmlDocument();
                xmlDocument.LoadXml(output);

                return xmlDocument;
            }

            return null;
        }

        /// <summary>
        /// Does the activity request.
        /// </summary>
        /// <param name="vimeoApiOutputFormatType">Type of the vimeo API output format.</param>
        /// <param name="vimeoApiActivityRequestType">Type of the vimeo API activity request.</param>
        /// <param name="username">The username.</param>
        /// <returns></returns>
        protected static string DoActivityRequest
            (VimeoApiOutputFormatType vimeoApiOutputFormatType, 
            VimeoApiActivityRequestType vimeoApiActivityRequestType, string username)
        {
            string url = string.Format(GlobalConstants.VimeoAPI.ActivityRequestUrlFormat, 
                username, GetVimeoApiActivityRequestTypeString(vimeoApiActivityRequestType), 
                GetVimeoApiOutputFormatTypeString(vimeoApiOutputFormatType));
            return ExecuteGetCommand(url, null, null);
        }

        /// <summary>
        /// Does the activity request as XML.
        /// </summary>
        /// <param name="vimeoApiActivityRequestType">Type of the vimeo API activity request.</param>
        /// <param name="username">The username.</param>
        /// <returns></returns>
        protected static XmlDocument DoActivityRequestAsXML
            (VimeoApiActivityRequestType vimeoApiActivityRequestType, string username)
        {
            string output = DoActivityRequest
                (VimeoApiOutputFormatType.XML, vimeoApiActivityRequestType, username);
            if (!string.IsNullOrEmpty(output))
            {
                var xmlDocument = new XmlDocument();
                xmlDocument.LoadXml(output);

                return xmlDocument;
            }

            return null;
        }

        /// <summary>
        /// Does the album request.
        /// </summary>
        /// <param name="vimeoApiOutputFormatType">Type of the vimeo API output format.</param>
        /// <param name="vimeoApiAlbumRequestType">Type of the vimeo API album request.</param>
        /// <param name="albumID">The album ID.</param>
        /// <returns></returns>
        protected static string DoAlbumRequest
            (VimeoApiOutputFormatType vimeoApiOutputFormatType, 
            VimeoApiAlbumRequestType vimeoApiAlbumRequestType, string albumID)
        {
            string url = string.Format(GlobalConstants.VimeoAPI.AlbumRequestUrlFormat, albumID,
            GetVimeoApiAlbumRequestTypeString(vimeoApiAlbumRequestType), 
            GetVimeoApiOutputFormatTypeString(vimeoApiOutputFormatType));
            return ExecuteGetCommand(url, null, null);
        }

        /// <summary>
        /// Does the album request as XML.
        /// </summary>
        /// <param name="vimeoApiAlbumRequestType">Type of the vimeo API album request.</param>
        /// <param name="albumId">The album id.</param>
        /// <returns></returns>
        protected static XmlDocument DoAlbumRequestAsXML
            (VimeoApiAlbumRequestType vimeoApiAlbumRequestType, string albumId)
        {
            string output = DoAlbumRequest(VimeoApiOutputFormatType.XML, 
                vimeoApiAlbumRequestType, albumId);
            if (!string.IsNullOrEmpty(output))
            {
                var xmlDocument = new XmlDocument();
                xmlDocument.LoadXml(output);

                return xmlDocument;
            }

            return null;
        }

        /// <summary>
        /// Does the channel request.
        /// </summary>
        /// <param name="vimeoApiOutputFormatType">Type of the vimeo API output format.</param>
        /// <param name="vimeoApiChannelRequestType">Type of the vimeo API channel request.</param>
        /// <param name="channelName">The channel ID.</param>
        /// <returns></returns>
        protected static string DoChannelRequest
            (VimeoApiOutputFormatType vimeoApiOutputFormatType, 
            VimeoApiChannelRequestType vimeoApiChannelRequestType, string channelName)
        {
            string url = string.Format(GlobalConstants.VimeoAPI.ChannelRequestUrlFormat, channelName,
            GetVimeoApiChannelRequestTypeString(vimeoApiChannelRequestType), 
            GetVimeoApiOutputFormatTypeString(vimeoApiOutputFormatType));
            return ExecuteGetCommand(url, null, null);
        }

        /// <summary>
        /// Does the channel request as XML.
        /// </summary>
        /// <param name="vimeoApiChannelRequestType">Type of the vimeo API channel request.</param>
        /// <param name="channelName">The channel id.</param>
        /// <returns></returns>
        protected static XmlDocument DoChannelRequestAsXML
            (VimeoApiChannelRequestType vimeoApiChannelRequestType, string channelName)
        {
            string output = DoChannelRequest(VimeoApiOutputFormatType.XML, 
                vimeoApiChannelRequestType, channelName);
            if (!string.IsNullOrEmpty(output))
            {
                var xmlDocument = new XmlDocument();
                xmlDocument.LoadXml(output);

                return xmlDocument;
            }

            return null;
        }

        /// <summary>
        /// Does the group request.
        /// </summary>
        /// <param name="vimeoApiOutputFormatType">Type of the vimeo API output format.</param>
        /// <param name="vimeoApiGroupRequestType">Type of the vimeo API group request.</param>
        /// <param name="groupName">The group ID.</param>
        /// <returns></returns>
        protected static string DoGroupRequest
            (VimeoApiOutputFormatType vimeoApiOutputFormatType, 
            VimeoApiGroupRequestType vimeoApiGroupRequestType, string groupName)
        {
            string url = string.Format(GlobalConstants.VimeoAPI.GroupRequestUrlFormat, groupName,
            GetVimeoApiGroupRequestTypeString(vimeoApiGroupRequestType), 
            GetVimeoApiOutputFormatTypeString(vimeoApiOutputFormatType));
            return ExecuteGetCommand(url, null, null);
        }

        /// <summary>
        /// Does the group request as XML.
        /// </summary>
        /// <param name="vimeoApiGroupRequestType">Type of the vimeo API group request.</param>
        /// <param name="groupName">The group id.</param>
        /// <returns></returns>
        protected static XmlDocument DoGroupRequestAsXML
            (VimeoApiGroupRequestType vimeoApiGroupRequestType, string groupName)
        {
            string output = DoGroupRequest(VimeoApiOutputFormatType.XML, 
                vimeoApiGroupRequestType, groupName);
            if (!string.IsNullOrEmpty(output))
            {
                var xmlDocument = new XmlDocument();
                xmlDocument.LoadXml(output);

                return xmlDocument;
            }

            return null;
        }
        #endregion

        #region Methods to convert vimeo enums to strings
        /// <summary>
        /// Gets the vimeo API activity request type string.
        /// </summary>
        /// <param name="vimeoApiActivityRequestType">Type of the vimeo API activity request.
        /// </param>
        /// <returns></returns>
        protected static string GetVimeoApiActivityRequestTypeString
            (VimeoApiActivityRequestType vimeoApiActivityRequestType)
        {
            return vimeoApiActivityRequestType.ToString().ToLower();
        }

        /// <summary>
        /// Gets the vimeo API album request type string.
        /// </summary>
        /// <param name="vimeoApiAlbumRequestType">Type of the vimeo API album request.
        /// </param>
        /// <returns></returns>
        protected static string GetVimeoApiAlbumRequestTypeString
            (VimeoApiAlbumRequestType vimeoApiAlbumRequestType)
        {
            return vimeoApiAlbumRequestType.ToString().ToLower();
        }

        /// <summary>
        /// Gets the vimeo API channel request type string.
        /// </summary>
        /// <param name="vimeoApiChannelRequestType">Type of the vimeo API channel request.
        /// </param>
        /// <returns></returns>
        protected static string GetVimeoApiChannelRequestTypeString
            (VimeoApiChannelRequestType vimeoApiChannelRequestType)
        {
            return vimeoApiChannelRequestType.ToString().ToLower();
        }

        /// <summary>
        /// Gets the vimeo API group request type string.
        /// </summary>
        /// <param name="vimeoApiGroupRequestType">Type of the vimeo API group request.
        /// </param>
        /// <returns></returns>
        protected static string GetVimeoApiGroupRequestTypeString
            (VimeoApiGroupRequestType vimeoApiGroupRequestType)
        {
            return vimeoApiGroupRequestType.ToString().ToLower();
        }

        /// <summary>
        /// Gets the vimeo API user request type string.
        /// </summary>
        /// <param name="vimeoApiUserRequestType">Type of the vimeo API user request.
        /// </param>
        /// <returns></returns>
        protected static string GetVimeoApiUserRequestTypeString
            (VimeoApiUserRequestType vimeoApiUserRequestType)
        {
            return vimeoApiUserRequestType.ToString().ToLower();
        }

        /// <summary>
        /// Gets the vimeo API output format type string.
        /// </summary>
        /// <param name="vimeoApiOutputFormatType">Type of the vimeo API output format.
        /// </param>
        /// <returns></returns>
        protected static string GetVimeoApiOutputFormatTypeString
            (VimeoApiOutputFormatType vimeoApiOutputFormatType)
        {
            return vimeoApiOutputFormatType.ToString().ToLower();
        }
        #endregion

        /// <summary>
        /// Gets the video title from vimeo.
        /// </summary>
        /// <param name="videoId">The video id.</param>
        /// <returns></returns>
        public static string GetVideoTitleFromVimeo(string videoId)
        {
            var video = GetVideoUsingVideoId(videoId);

            return video == null ? string.Empty : video.title;
        }

        /// <summary>
        /// Gets the embedded player HTML.
        /// </summary>
        /// <param name="videoId">The video id.</param>
        /// <returns></returns>
        public static string GetEmbeddedPlayerHTML(string videoId)
        {
            var doc = DoOembedRequestAsXML(videoId);

            var serializer = new XmlSerializer(typeof(OEmbed));

            var stringReader = new StringReader(doc.OuterXml);
            var xmlReader = new XmlTextReader(stringReader);

            var oembed = (OEmbed)serializer.Deserialize(xmlReader);

            return oembed.html;
        }

        /// <summary>
        /// Gets the vimeo video id from URL.
        /// </summary>
        /// <param name="videoURL">The video URL.</param>
        /// <returns>The video Id</returns>
        public static string GetVimeoVideoIdFromURL(string videoURL)
        {
            if (videoURL.Contains("/"))
            {
                var splitter = videoURL.Split(new[] {'/'});

                return splitter[splitter.Length - 1];
            }
            
            int v;
            return int.TryParse(videoURL, out v) ? videoURL : string.Empty;
        }

        /// <summary>
        /// Gets the video using video id.
        /// </summary>
        /// <param name="videoId">The video id.</param>
        /// <returns>VimeoVideo object</returns>
        public static VimeoVideo GetVideoUsingVideoId(string videoId)
        {
            var xmldoc = RequestInXML.Video.GetVideo(videoId);

            var serializer = new XmlSerializer(typeof(VimeoVideoWrapper));

            var stringReader = new StringReader(xmldoc.OuterXml);
            var xmlReader = new XmlTextReader(stringReader);

            var video = (VimeoVideoWrapper)serializer.Deserialize(xmlReader);

            if (video.Videos == null || video.Videos.Length == 0)
                return null;

            return video.Videos[0];
        }

        /// <summary>
        /// Builds the vimeo search response.
        /// </summary>
        /// <param name="xmldoc">The xmldoc.</param>
        /// <returns></returns>
        public static VimeoSearchResponse BuildVimeoSearchResponse(XmlDocument xmldoc)
        {
            try
            {
                var serializer = new XmlSerializer(typeof(VimeoSearchResponse));

                var stringReader = new StringReader(xmldoc.OuterXml);
                var xmlReader = new XmlTextReader(stringReader);

                return (VimeoSearchResponse) serializer.Deserialize(xmlReader);
            }
            catch {}

            return null;
        }

        /// <summary>
        /// Builds the vimeo video thumbnails response.
        /// </summary>
        /// <param name="xmldoc">The xmldoc.</param>
        /// <returns></returns>
        public static VimeoVideoThumbnailsResponse BuildVimeoVideoThumbnailsResponse
            (XmlDocument xmldoc)
        {
            try
            {
                var serializer = new XmlSerializer(typeof(VimeoVideoThumbnailsResponse));

                var stringReader = new StringReader(xmldoc.OuterXml);
                var xmlReader = new XmlTextReader(stringReader);

                return (VimeoVideoThumbnailsResponse)serializer.Deserialize(xmlReader);
            }
            catch { }

            return null;
        }

        /// <summary>
        /// Builds the vimeo error response.
        /// </summary>
        /// <param name="xmldoc">The xmldoc.</param>
        /// <returns></returns>
        public static VimeoErrorResponse BuildVimeoErrorResponse(XmlDocument xmldoc)
        {
            try
            {
                var serializer = new XmlSerializer(typeof(VimeoErrorResponse));

                var stringReader = new StringReader(xmldoc.OuterXml);
                var xmlReader = new XmlTextReader(stringReader);

                return (VimeoErrorResponse)serializer.Deserialize(xmlReader);
            }
            catch { }

            return null;
        }

        /// <summary>
        /// Searches the specified query.
        /// </summary>
        /// <param name="query">The query.</param>
        /// <returns></returns>
        public static XmlDocument Search(string query)
        {
            try
            {
                return DoSearchRequest(query);
            }
            catch { }

            return null;
        }

        /// <summary>
        /// Gets the video thumbnails.
        /// </summary>
        /// <param name="videoId">The video id.</param>
        /// <returns></returns>
        public static XmlDocument GetVideoThumbnails(string videoId)
        {
            try
            {
                return DoGetVideoThumbnailsRequest(videoId);
            }
            catch { }

            return null;
        }

        /// <summary>
        /// Checks the query worked ok.
        /// </summary>
        /// <param name="xmldoc">The xmldoc.</param>
        /// <returns></returns>
        public static bool QueryIsOk(XmlDocument xmldoc)
        {
            try
            {
                if (xmldoc.DocumentElement != null)
                    return xmldoc.DocumentElement.GetAttribute("stat").Equals("ok");
            }
            catch { }

            return false;
        }
    }
}

 

This is our wrapper of the Vimeo API. As I mentioned at the start there are a lot of methods in here that are not needed for this project, but if you are planning to get more involved with the Vimeo API I’m sure you’ll be grateful that they’re there!

Next we’ll add a couple of pages to our web application.

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" 
Inherits="Vimeo.Default" %>
<%@ Import Namespace="Common" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Vimeo test</title>
</head>
<body>
    <form id="form1" runat="server">
        <label>Search Vimeo:</label> 
        <asp:TextBox ID="VimeoSearchQuery" runat="server"></asp:TextBox> 
        <asp:LinkButton ID="VimeoSearchQueryBtn" runat="server" 
            OnClick="VimeoSearchQueryBtn_Click" Text="Search"></asp:LinkButton>

        <asp:Label ID="ErrorMessage" runat="server" Visible="false"></asp:Label>
                
        <asp:PlaceHolder ID="phSearchResults" runat="server"></asp:PlaceHolder>
        
        <div id="divSearchResults">
            <asp:Repeater ID="SearchResultsRepeater" runat="server">
                <ItemTemplate>
                <div>
                    <a href="<%= GlobalConstants.Links.ViewVideo %>
                        <%#DataBinder.Eval(Container.DataItem, "VideoId")%>">
                            <%#DataBinder.Eval(Container.DataItem, "Thumbnail")%>
                    </a>
                    <br />
                    <a href="<%= GlobalConstants.Links.ViewVideo %>
                        <%#DataBinder.Eval(Container.DataItem, "VideoId")%>">
                            <%#DataBinder.Eval(Container.DataItem, "Title")%>
                    </a>
                </div>
                </ItemTemplate>
            </asp:Repeater>
        </div>
    </form>
</body>
</html>

Default.aspx.cs

using System;
using System.Collections.Generic;
using System.Web.UI;
using BusinessObject;
using BusinessObject.Enums;
using Common;

namespace Vimeo
{
    public partial class Default : Page
    {
        /// <summary>
        /// Handles the Click event of the VimeoSearchQueryBtn control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> 
        /// instance containing the event data.</param>
        protected void VimeoSearchQueryBtn_Click(object sender, EventArgs e)
        {
            var response = VimeoAPI.Search(VimeoSearchQuery.Text);

            if (VimeoAPI.QueryIsOk(response))
            {
                var vimeoSearchResponse = VimeoAPI.BuildVimeoSearchResponse(response);

                var videoList = new List<VideoExtracted>();

                if (vimeoSearchResponse.videos.total != "0")
                {
                    foreach (var video in vimeoSearchResponse.videos.video)
                    {
                        var thumbnail = GetMediumVimeoThumbnail(video.id);

                        if (!string.IsNullOrEmpty(thumbnail))
                            videoList.Add(new VideoExtracted
                            {
                                Thumbnail = "<img src=\"" + thumbnail + "\" />",
                                Title = video.title,
                                VideoId = video.id
                            });
                    }
                }

                BindSearchRepeaterAndAddToCache(videoList);
            }
            else
            {
                var vimeoErrorResponse = VimeoAPI.BuildVimeoErrorResponse(response);

                DisplayErrorMessage(
                    (VimeoApiErrorCode) Convert.ToInt32(vimeoErrorResponse.error.code) ==
                        VimeoApiErrorCode.ServiceCurrentlyUnavailable
                            ? GlobalConstants.ErrorMessages.SearchServiceUnavailable
                            : GlobalConstants.ErrorMessages.SearchError);
            }
        }

        /// <summary>
        /// Binds the search repeater add add to cache.
        /// </summary>
        /// <param name="videoList">The video list.</param>
        private void BindSearchRepeaterAndAddToCache(IEnumerable<VideoExtracted> videoList)
        {
            SearchResultsRepeater.DataSource = videoList;
            SearchResultsRepeater.DataBind();

            if (SearchResultsRepeater.Items.Count > 0)
                phSearchResults.Visible = true;
            else
            {
                DisplayErrorMessage(GlobalConstants.ErrorMessages.NoSearchResults);
                phSearchResults.Visible = false;
            }
        }

        /// <summary>
        /// Gets the medium vimeo thumbnail.
        /// </summary>
        /// <param name="videoId">The video id.</param>
        /// <returns></returns>
        protected string GetMediumVimeoThumbnail(string videoId)
        {
            var response = VimeoAPI.GetVideoThumbnails(videoId);

            if (VimeoAPI.QueryIsOk(response))
            {
                var vimeoVideoThumbnailsResponse = 
                    VimeoAPI.BuildVimeoVideoThumbnailsResponse(response);

                return vimeoVideoThumbnailsResponse.thumbnails.thumbnail[1].thumbnail;
            }

            return null;
        }

        /// <summary>
        /// Displays the error message.
        /// </summary>
        /// <param name="errorMessage">The error message.</param>
        private void DisplayErrorMessage(string errorMessage)
        {
            ErrorMessage.Visible = true;
            ErrorMessage.Text = errorMessage;
            return;
        }
    }
}

So what’s going on here? Well when we click the search button on the front page we call our VimeoAPI.Search() method with the search text. The VimeoAPI.Search method then calls several methods within our VimeoAPI wrapper. First it creates an OAuth request url with our consumer key, consumer secret and search query in BuildOAuthApiRequestUrl() and DoSearchRequest(), then it calls the Vimeo web service in ExecuteGetCommand() method. ExecuteGetCommand() return an XML response which is then loaded into an XmlDocument() which we return to the Default.aspx.cs VimeoSearchQueryBtn_Click() method.

Once the code behind gets the XmlDocument we check the response code is valid by calling VimeoAPI.QueryIsOk(). If the response is not OK we output an error message, otherwise we serialize the XmlDocument into our VimeoVideo class using VimeoAPI.BuildVimeoSearchResponse().

This is the basics behind any call you will make to the VimeoAPI and it is simply a case of ensuring you have the correct request URL with valid consumer key and consumer secret, and a serializable class (if you want to take the serialize route and aren’t going to manually wade through the XML!) to put the XML response from your call in to.

For the purposes of this example I have created a List<VideoExtracted>() item to which I add each video returned by the search call to the API along with a thumbnail for that video which I have to get by calling the API for each video. It would be nice if the thumbnails were returned with the search list of videos, but at the time of writing that isn’t the case.

Bind this list of VideoExtracted items to our repeater and this page is done.

Lastly, the video viewer page.

ViewVideo.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ViewVideo.aspx.cs" 
    Inherits="Vimeo.ViewVideo" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Vimeo Player Test</title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <h2><asp:Literal ID="VideoTitle" runat="server"></asp:Literal></h2><br />
        
            <p><asp:Literal ID="VideoDescription" runat="server"></asp:Literal></p>

            <div id="thevideo" runat="server"></div>
        </div>
    </form>
</body>
</html>

ViewVideo.aspx.cs

using System;
using System.Web.UI;
using Common;

namespace Vimeo
{
    public partial class ViewVideo : Page
    {
        /// <summary>
        /// Handles the Load event of the Page control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> 
        /// instance containing the event data.</param>
        protected void Page_Load(object sender, EventArgs e)
        {
            var vidId = Request.QueryString[GlobalConstants.Querystring.Video];

            thevideo.InnerHtml = VimeoAPI.GetEmbeddedPlayerHTML(vidId);

            var video = VimeoAPI.GetVideoUsingVideoId(vidId);

            VideoTitle.Text = video.title;
            VideoDescription.Text = video.description;
        }

        /// <summary>
        /// Replaces the line break with BR.
        /// </summary>
        /// <param name="s">The s.</param>
        /// <returns></returns>
        public static string ReplaceLineBreakWithBR(string s)
        {
            return s.Replace("\r\n", "<br />").Replace("\n", "<br />");
        }
    }
}

 

Very simple, a video id is passed in the querystring, retrieved in the Page_Load() method of the page and the video details are retrieved by calling the VimeoAPI.GetVideoUsingVideoId() method. the HTML for the video to display on the page is built by performing an OEmbed request to the Vimeo API using the VimeoAPI.DoOembedRequestAsXML() method. This again uses our VimeoAPI.ExecuteGetCommand() method and works like the other requests we have seen.

Conclusion

I hope that was relatively painless and makes sense. As always the best way to fully understand what’s going on in the code is to download the source and have a play around with it. Until next time…  :o)

Tags:

Share |

Getting Started With The YouTube API in C#

Share |
by Rob 4. August 2010 10:23

I recently had to provide a code solution that retrieved a YouTube user’s favourite videos and displays them to a web page. Clicking on any one of this list of videos would then open that video in a new page ready to play. Luckily Google has set up an easy to use YouTube API for .NET we can use.

You can download the source files for this solution here.

Google Developer Key and API DLLs

Before we start there are a couple of things we need to do. To access Google’s API we need a developer key. To sign up for a developer key go to http://code.google.com/apis/youtube/dashboard and follow the instructions. Once we have out key we need to get the Google API DLL’s to reference in our solution. We can do this one of 2 ways:

  1. 1. Download and install the Google Data SDK and retrieve the DLL’s from the YouTube sample by going to http://code.google.com/p/google-gdata/downloads/list
  2. 2. Just get the DLL’s required by browsing the Bin folder of the YouTube sample here http://code.google.com/p/google-gdata/source/browse/trunk/clients/cs/samples/YouTubeSample/?r=570#YouTubeSample/Bin.

 

The DLL’s are included in the source files in my test solution so alternatively you can just download this.

The Code

I have separated the solution into 3 projects, the web application and 2 class libraries. We’ll start with our BusinessObject class library.

VideoExtracted.cs

namespace BusinessObject
{
    public class VideoExtracted
    {
        public string VideoId { get; set; }
        public string Title { get; set; }
        public string Thumbnail { get; set; }
        public string Description { get; set; }
    }
}

This is a wrapper for the video information we want returned from the YouTube API.

YouTubePlayer.cs

namespace BusinessObject
{
    /// <summary>
    /// Wrapper for all the settings for the You Tube embedded player
    /// </summary>
    public class YouTubePlayer
    {
        public YouTubePlayer()
        {
            LoadRelatedVideos = 1;
            AutoPlay = 0;
            Loop = 0;
            EnableJavaScriptAPI = 0;
            PlayerAPIId = string.Empty;
            DisableKeyboard = 0;
            EnhancedGenieMenu = 0;
            Border = 0;
            PrimaryBorderColor = "#FFFFFF";
            SecondaryBorderColor = "#FFFFFF";
            SecondsFromStart = 0;
            FullScreen = 1;
            HD = 0;
            ShowSearchBox = 0;
            ShowVideoInfo = 0;
            VideoAnnotations = 3;
        }

        /// <summary>
        /// Values: 0 or 1. Default is 1. Sets whether the player should load related videos once playback of the initial video starts. 
        /// Related videos are displayed in the "genie menu" when the menu button is pressed. 
        /// The player search functionality will be disabled if rel is set to 0.
        /// </summary>
        /// <value>0 or 1</value>
        public int LoadRelatedVideos { get; set; }

        /// <summary>
        /// Values: 0 or 1. Default is 0. Sets whether or not the initial video will autoplay when the player loads.
        /// </summary>
        /// <value>0 or 1</value>
        public int AutoPlay { get; set; }

        /// <summary>
        /// Values: 0 or 1. Default is 0. In the case of a single video player, a setting of 1 will cause the player to play the initial video again 
        /// and again. In the case of a playlist player (or custom player), the player will play the entire playlist and then start again at the first video.
        /// </summary>
        /// <value>0 or 1</value>
        public int Loop { get; set; }

        /// <summary>
        /// Values: 0 or 1. Default is 0. Setting this to 1 will enable the Javascript API. For more information on the Javascript API 
        /// and how to use it, see the JavaScript API documentation.
        /// </summary>
        /// <see cref="http://code.google.com/apis/youtube/js_api_reference.html"/>
        /// <value>0 or 1</value>
        public int EnableJavaScriptAPI { get; set; }

        /// <summary>
        /// Value can be any alphanumeric string. This setting is used in conjunction with the JavaScript API. See the JavaScript API documentation for details.
        /// </summary>
        /// <see cref="http://code.google.com/apis/youtube/js_api_reference.html"/>
        /// <value>The player API id (any alphanumeric string)</value>
        public string PlayerAPIId { get; set; }

        /// <summary>
        /// Values: 0 or 1. Default is 0. Setting to 1 will disable the player keyboard controls. Keyboard controls are as follows: 
        /// Spacebar: Play / Pause 
        /// Arrow Left: Restart current video 
        /// Arrow Right: Jump ahead 10% in the current video 
        /// Arrow Up: Volume up 
        /// Arrow Down: Volume Down
        /// </summary>
        /// <value>0 or 1</value>
        public int DisableKeyboard { get; set; }

        /// <summary>
        /// Values: 0 or 1. Default is 0. Setting to 1 enables the "Enhanced Genie Menu". This behavior causes the genie menu (if present) to appear 
        /// when the user's mouse enters the video display area, as opposed to only appearing when the menu button is pressed.
        /// </summary>
        /// <value>0 or 1</value>
        public int EnhancedGenieMenu { get; set; }

        /// <summary>
        /// Values: 0 or 1. Default is 0. Setting to 1 enables a border around the entire video player. The border's primary color can be set via 
        /// the color1 (PrimaryBorderColor) parameter, and a secondary color can be set by the color2 (SecondaryBorderColor) parameter.
        /// </summary>
        /// <value>0 or 1</value>
        public int Border { get; set; }

        /// <summary>
        /// Values: Any RGB value in hexadecimal format. This is the primary border color.
        /// </summary>
        /// <value>RGB value in hexadecimal format</value>
        public string PrimaryBorderColor { get; set; }

        /// <summary>
        /// Values: Any RGB value in hexadecimal format. This is the video control bar background color and secondary border color.
        /// </summary>
        /// <value>RGB value in hexadecimal format</value>
        public string SecondaryBorderColor { get; set; }

        /// <summary>
        /// Values: A positive integer. This parameter causes the player to begin playing the video at the given number of seconds from the start of the video. 
        /// Similar to the seekTo function, the player will look for the closest keyframe to the time you specify. 
        /// This means sometimes the play head may seek to just before the requested time, usually no more than ~2 seconds.
        /// </summary>
        /// <value>A positive integer</value>
        public int SecondsFromStart { get; set; }

        /// <summary>
        /// Values: 0 or 1. Default is 0. Setting to 1 enables the fullscreen button. This has no effect on the Chromeless Player. 
        /// Note that you must include some extra arguments to your embed code for this to work. The param allowfullscreen of the below example enable fullscreen functionality:
        /// </summary>
        /// <value>0 or 1</value>
        // <object width="425" height="344">
        // <param name="movie" value="http://www.youtube.com/v/u1zgFlCw8Aw&fs=1"</param>
        // <param name="allowFullScreen" value="true"></param>
        // <embed src="http://www.youtube.com/v/u1zgFlCw8Aw&fs=1"
        // type="application/x-shockwave-flash"
        // allowfullscreen="true"
        // width="425" height="344">
        // </embed>
        // </object>
        public int FullScreen { get; set; }

        /// <summary>
        /// Values: 0 or 1. Default is 0. Setting to 1 enables HD playback by default. This has no effect on the Chromeless Player. 
        /// This also has no effect if an HD version of the video is not available. If you enable this option, keep in mind that users with a 
        /// slower connection may have an sub-optimal experience unless they turn off HD. You should ensure your player is large enough to 
        /// display the video in its native resolution.
        /// </summary>
        /// <value>0 or 1</value>
        public int HD { get; set; }

        /// <summary>
        /// Values: 0 or 1. Default is 1. Setting to 0 disables the search box from displaying when the video is minimized. 
        /// If the rel (LoadRelatedVideos) parameter is set to 0 then the search box will also be disabled, regardless of the value of showsearch.
        /// </summary>
        /// <value>0 or 1</value>
        public int ShowSearchBox { get; set; }

        /// <summary>
        /// Values: 0 or 1. Default is 1. Setting to 0 causes the player to not display information like the video title and rating before the video starts playing.
        /// </summary>
        /// <value>0 or 1</value>
        public int ShowVideoInfo { get; set; }

        /// <summary>
        /// Values: 1 or 3. Default is 1. Setting to 1 will cause video annotations to be shown by default, whereas setting to 3 will cause video annotation to not be shown by default.
        /// </summary>
        /// <value>1 or 3</value>
        public int VideoAnnotations { get; set; }
    }
}

 

This is a wrapper for embedding our YouTube player – we’ll need this later on.

 

Now we need to create our Common class library. The Google DLLs need to be referenced in this library. I add them to the web application bin folder and reference them from there as we will also need them referenced in the web application, but you can store them wherever you wish.

GlobalConstants.cs

I always have a class with stongly-typed items for use in my solution contained in this file.

namespace Common
{
    /// <summary>
    /// Global constants for the solution
    /// </summary>
    public class GlobalConstants
    {
        #region GoogleAPI
        /// <summary>
        /// Constants required to use the Google API
        /// </summary>
        public class GoogleAPI
        {
            public const string YouTubeAccountName = "tross200sx";
            /// <summary>
            /// YouTube player width
            /// </summary>
            public const string YouTubePlayerWidth = "425";
            /// <summary>
            /// YouTube player height
            /// </summary>
            public const string YouTubePlayerHeight = "355";
            /// <summary>
            /// Google API Developer Key - your developer key
            /// </summary>
            public const string DeveloperKey = "your developer key";
            /// <summary>
            /// http://gdata.youtube.com - required for Authsub
            /// </summary>
            public const string YouTubeScope = "http://gdata.youtube.com";
            /// <summary>
            /// http://gdata.youtube.com/feeds/api/videos/ - used to get Video object
            /// </summary>
            public const string VideoEntryURL = YouTubeScope + "/feeds/api/videos/";
        }
        #endregion

        #region Links
        /// <summary>
        /// Page links
        /// </summary>
        public class Links
        {
            /// <summary>
            /// Default.aspx
            /// </summary>
            public const string Default = "/Default.aspx";
            /// <summary>
            /// ViewVideo.aspx?vid=
            /// </summary>
            public const string ViewVideo = "/ViewVideo.aspx?" + Querystring.Video + "=";
        }
        #endregion

        #region Querystring
        /// <summary>
        /// Querystring identifiers
        /// </summary>
        public class Querystring
        {
            /// <summary>
            /// vid
            /// </summary>
            public const string Video = "vid";
        }
        #endregion
    }
}

You will need to put your own developer key into this class, and you may also wish to change the YouTube account name.

GoogleAPI.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BusinessObject;
using Google.YouTube;

namespace Common
{
    public class GoogleAPI
    {
        protected IList<Video> Videos = new List<Video>();

        /// <summary>
        /// Gets a YouTube request object.
        /// </summary>
        /// <returns>YouTubeRequest</returns>
        public YouTubeRequest GetYouTubeRequestObject()
        {
            var youTubeRequestSettings = new YouTubeRequestSettings(GlobalConstants.GoogleAPI.YouTubeAccountName, string.Empty, GlobalConstants.GoogleAPI.DeveloperKey);
            return new YouTubeRequest(youTubeRequestSettings);
        }

        /// <summary>
        /// Gets favourite videos by user name.
        /// </summary>
        /// <param name="username">The username.</param>
        /// <returns>IEnumerable VideoExtracted</returns>
        public IEnumerable<Video> GetFavouriteVideosByUserName(string username)
        {
            var feed = GetYouTubeRequestObject().GetFavoriteFeed(username);
            return feed.Entries;
        }

        /// <summary>
        /// Gets the favourite videos by user name_ list.
        /// </summary>
        /// <param name="username">The username.</param>
        /// <returns></returns>
        public IList<Video> GetFavouriteVideosByUserName_List(string username)
        {
            return GetFavouriteVideosByUserName(username).ToList();
        }

        /// <summary>
        /// Gets the favourite videos extracted by user name_ list.
        /// </summary>
        /// <param name="username">The username.</param>
        /// <returns></returns>
        public IList<VideoExtracted> GetFavouriteVideosExtractedByUserName_List(string username)
        {
            return ExtractYouTubeVideoList(GetFavouriteVideosByUserName_List(username));
        }

        /// <summary>
        /// Extracts you tube video.
        /// </summary>
        /// <param name="video">The video.</param>
        /// <returns></returns>
        public VideoExtracted ExtractYouTubeVideo(Video video)
        {
            var videoExtracted = new VideoExtracted
                                     {
                                         VideoId = video.VideoId, 
                                         Title = video.Title, 
                                         Description = video.Description
                                     };

            if (video.Thumbnails.Count > 0)
                videoExtracted.Thumbnail = "<img src=\"" + video.Thumbnails[0].Url + "\" alt=\"" + videoExtracted.Title + "\" />";

            return videoExtracted;
        }

        /// <summary>
        /// Extracts you tube video list.
        /// </summary>
        /// <param name="videoList">The video list.</param>
        /// <returns></returns>
        public IList<VideoExtracted> ExtractYouTubeVideoList(IList<Video> videoList)
        {
            return videoList.Select(ExtractYouTubeVideo).ToList();
        }

        /// <summary>
        /// Gets the embedded player HTML using default settings.
        /// </summary>
        /// <param name="videoId">The video id.</param>
        /// <example>
        /// <code>
        /// div_to_hold_player.InnerHtml = googleAPI.GetEmbeddedPlayerHTML(video_id)
        /// </code>
        /// </example>
        /// <returns>html string for inserting embedded player</returns>
        public string GetEmbeddedPlayerHTML(string videoId)
        {
            return GetPlayerCode(videoId + EncodePlayerSettingsFromYouTubePlayerObjectToQueryString(new YouTubePlayer()));
        }

        /// <summary>
        /// Encodes the player settings from you tube player object to query string.
        /// </summary>
        /// <param name="player">The YouTubePlayer.</param>
        /// <returns>string (encoded querystring)</returns>
        private static string EncodePlayerSettingsFromYouTubePlayerObjectToQueryString(YouTubePlayer player)
        {
            var sb = new StringBuilder();

            sb.Append("?rel=" + player.LoadRelatedVideos);

            if (player.AutoPlay == 1) 
                sb.Append("&autoplay=" + player.AutoPlay);

            if (player.Loop == 1) 
                sb.Append("&loop=" + player.Loop);

            if (player.EnableJavaScriptAPI == 1) 
                sb.Append("&enablejsapi=" + player.EnableJavaScriptAPI);
            
            sb.Append("&playerapiid=" + player.PlayerAPIId);

            if (player.DisableKeyboard == 1) 
                sb.Append("&disablekb=" + player.DisableKeyboard);

            if (player.EnhancedGenieMenu == 1) 
                sb.Append("&egm=" + player.EnhancedGenieMenu);

            if (player.Border == 1) 
                sb.Append("&border=" + player.Border);

            if (!string.IsNullOrEmpty(player.PrimaryBorderColor)) 
                sb.Append("&color1=" + player.PrimaryBorderColor);

            if (!string.IsNullOrEmpty(player.SecondaryBorderColor)) 
                sb.Append("&color2=" + player.SecondaryBorderColor);

            if (player.SecondsFromStart > 0) 
                sb.Append("&start=" + player.SecondsFromStart);

            if (player.FullScreen == 1) 
                sb.Append("&fs=" + player.FullScreen);

            if (player.HD == 1) 
                sb.Append("&hd=" + player.HD);

            if (player.ShowSearchBox == 0) 
                sb.Append("&showsearch=" + player.ShowSearchBox);

            if (player.ShowVideoInfo == 0) 
                sb.Append("&showinfo=" + player.ShowVideoInfo);

            if (player.VideoAnnotations == 3) 
                sb.Append("&iv_load_policy=" + player.VideoAnnotations);

            return sb.ToString();
        }

        /// <summary>
        /// Gets the player code.
        /// </summary>
        /// <param name="videoURL">The video URL.</param>
        /// <returns></returns>
        private static string GetPlayerCode(string videoURL)
        {
            var sb = new StringBuilder();

            sb.Append("<object width=\"" + GlobalConstants.GoogleAPI.YouTubePlayerWidth + "\" height=\"" + GlobalConstants.GoogleAPI.YouTubePlayerHeight + "\">");
            sb.Append("<param name=\"movie\" value=\"http://www.youtube.com/v/" + videoURL + "\"></param>");
            sb.Append("<param name=\"allowFullScreen\" value=\"true\"></param>");
            sb.Append("<embed src=\"http://www.youtube.com/v/" + videoURL + "\" type=\"application/x-shockwave-flash\" width=\"" 
                + GlobalConstants.GoogleAPI.YouTubePlayerWidth + "\" height=\"" 
                + GlobalConstants.GoogleAPI.YouTubePlayerHeight + "\" allowfullscreen=\"true\"></embed>");
            sb.Append("</object>");

            return sb.ToString();
        }

        /// <summary>
        /// Gets the video using video id.
        /// </summary>
        /// <param name="videoId">The video id.</param>
        /// <returns>Video object</returns>
        public Video GetVideoUsingVideoId(string videoId)
        {
            var videoEntryUrl = new Uri(GlobalConstants.GoogleAPI.VideoEntryURL + videoId);

            try
            {
                return GetYouTubeRequestObject().Retrieve<Video>(videoEntryUrl);
            }
            catch (Exception)
            {
                return null;
            }
        }
    }
}

 

I won’t go into too much detail here as the process is really quite simple. We have to build a YouTubeRequestObject which we then use to call different methods in the YouTube API. In this case we are using the GetFavoriteFeed() and Retrieve<Google.YouTube.Video>() methods to return the data we need.

 

And now on to the web application. To display our favourite feed videos we need to create an instance of the GoogleAPI in our Page_Load section and call the GetFavouriteVideosExtractedByUserName_List() method. I will bind the returned data to a repeater to keep things simple.

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="YouTube.Default" %>
<%@ Import Namespace="Common" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>YouTube test</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Repeater ID="VideoRepeater" runat="server">
            <ItemTemplate>
            <p>
                <a href="<%=GlobalConstants.Links.ViewVideo %><%#DataBinder.Eval(Container.DataItem, "VideoId")%>">
                    <%#DataBinder.Eval(Container.DataItem, "Thumbnail")%>
                </a>
                <br />
                <a href="<%=GlobalConstants.Links.ViewVideo %><%#DataBinder.Eval(Container.DataItem, "VideoId")%>">
                    <%#DataBinder.Eval(Container.DataItem, "Title")%>
                </a>
            </p>
            </ItemTemplate>
        </asp:Repeater>
    </div>
    </form>
</body>
</html>

I’m binding the title and YouTube thumbnail for display and wrapping both in anchor tags. these anchors point to our YouTube player page with the VideoId of the YouTube video in the querystring.

Default.aspx.cs

using System;
using System.Web.UI;
using Common;

namespace YouTube
{
    public partial class Default : Page
    {
        /// <summary>
        /// Handles the Load event of the Page control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        protected void Page_Load(object sender, EventArgs e)
        {
            var googleAPI = new GoogleAPI();

            VideoRepeater.DataSource = googleAPI.GetFavouriteVideosExtractedByUserName_List(GlobalConstants.GoogleAPI.YouTubeAccountName);
            VideoRepeater.DataBind();
        }
    }
}

Now we have our video list from our favourite feed displaying nicely, it’s time to create a page to play the videos. To do this I pass the video id of the YouTube video in the querystring and use this to get the video from a YouTube API call to get the video information (title, description, etc.)

To display the player on the page we need to use the standard object and embed HTML tags. This HTML is set up in the GetPlayerCode() method in the GoogleAPI.cs class.

We have lots of options when displaying a video, all of which are covered in our YouTubePlayer class in the BusinessObject class library. Any options we want to include are added on tot he querysting of the video url we use in our embed HTML statement. Have a run through the code and it should all make sense. Leaving the settings as they are is fine – the video will work as you would expect – but it’s useful to have the wrapper available should you want to change any of the settings.

ViewVideo.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ViewVideo.aspx.cs" Inherits="YouTube.ViewVideo" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>YouTube Player Test</title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <h2><asp:Literal ID="VideoTitle" runat="server"></asp:Literal></h2><br />
        
            <p><asp:Literal ID="VideoDescription" runat="server"></asp:Literal></p>

            <div id="thevideo" runat="server"></div>
        </div>
    </form>
</body>
</html>

 

A very simple page that has 2 literals for the YouTube video title and description, and a div into which we will inject our embed HTML statement.

ViewVideo.aspx.cs

using System;
using System.Web.UI;
using Common;

namespace YouTube
{
    public partial class ViewVideo : Page
    {
        /// <summary>
        /// Handles the Load event of the Page control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        protected void Page_Load(object sender, EventArgs e)
        {
            var googleAPI = new GoogleAPI();

            var vidId = Request.QueryString[GlobalConstants.Querystring.Video];

            thevideo.InnerHtml = googleAPI.GetEmbeddedPlayerHTML(vidId);

            var youTubeVideo = googleAPI.GetVideoUsingVideoId(vidId);

            VideoTitle.Text = youTubeVideo.Title;
            VideoDescription.Text = ReplaceLineBreakWithBR(youTubeVideo.Description);
        }

        /// <summary>
        /// Replaces the line break with BR.
        /// </summary>
        /// <param name="s">The s.</param>
        /// <returns></returns>
        public static string ReplaceLineBreakWithBR(string s)
        {
            return s.Replace("\r\n", "<br />").Replace("\n", "<br />");
        }
    }
}

 

I have added a ReplaceLineBreakWithBR() method here to make any line breaks HTML breaks as the YouTube video description uses newline characters and these won’t display on our page.

Conclusion

That’s all there is to it. There are loads more methods the Google API allows but hopefully if you’re just getting started this will ease your way in to the process!

Share |

Welcome

Share |
by Rob 3. August 2010 14:43

Hello and welcome to my blog.

I'm currently working as a .NET C# web developer for InsureandGo.com, a company specialising in Travel Insurance. In my spare time I have, along with my friend John Player, developed a social networking website called JDMLegion.com. I realise social networking websites are ten a penny nowadays and it's hard to get excited about yet another example, but John and I developed this site more as a hobby than a serious business venture. Our brief from the start was to build something that would be an excellent online CV for our talents in web development and design. We currently have just over 100 Japanese Domestic Market (in case you weren't sure what the JDM stood for!) car fans signed up and that number is growing daily.

I have another car-related website called JustSkylines.com. This started out as an online repository - a place for me to store user manuals and information that I could easily access from any computer when I needed to work on my car. It occurred to me that others may find the information useful, so decided to turn it into a website. I don't get much time to keep the site up-to-date, but being a reference repository means that I don't really need to do a great deal for the site to remain useful to thousands of car enthusiasts. In it's first year JustSkylines.com had 28,500 visitors from all over the world, and currently has just under 200 visitors per day.

As is no doubt apparent, when I'm not behind a computer I'm doing something with cars. My dad owns a workshop which he lets me use whenever I like, which puts me in the rather unique situation of being able to do a lot of work on cars without having to worry about the weather! I and several of my friends have modified cars which require plenty of upkeep and as a result I am down the workshop most weekends getting covered in oil.

This aim of this blog is to report on the bits I find interesting from these 2 walks of life, or anything else I think might be of interest.

Stay tuned and thanks for reading.

Tags:

Share |

Contact   |   Archive   |   Log in

Powered by BlogEngine.NET 1.6.1.0