The CanvasIFrameMasterPage class in Facebook.Web.dll
contains all the properties and methods that you need to access
Facebook data. The main class that you use in the Facebook SDK is Facebook.Rest.Api. This class is the window into the world of Facebook development. If you created the Weather2.aspx file to use the master page , accessing this class from code is as easy as the following line:
this.Master.Api
This class provides
many methods and properties for accessing Facebook data, but perhaps the
easiest and most efficient is through the use of the Facebook Query
Language (FQL). You can find out more about FQL from http://wiki.developers.facebook.com/index.php/FQL.
FQL uses a Structured Query Language (SQL) syntax to access data from
the Facebook databases and is more efficient because the SDK allows you
to batch queries into a MultiQuery
object for execution. Executing multiple queries at once saves
round-trip accesses to Facebook servers from across the network. In the PageLoad event of Weather2.aspx,
you can get the profile information of the logged-in user as well as
information about friends of the logged in user as follows:
protected void Page_Load(object sender, EventArgs e)
{
System.Console.WriteLine(this.Master.Api.Session.UserId);
this.Master.Api.Connect.Session.Login();
long userId = this.Master.Api.Users.GetLoggedInUser();
Dictionary<string, string> multiQuery = new Dictionary<string,
string<();
multiQuery.Add("query1", "SELECT name, current_location,pic_square
from user WHERE uid=" + userId);
multiQuery.Add("query2", "SELECT name, current_location, pic_square,
uid from user WHERE uid IN (SELECT uid2 from friend WHERE uid1="+ userId +
")");
foreach (Facebook.Schema.fql_result fqlResult in this.Master.Api.Fql.
Multiquery(multiQuery))
{
if (fqlResult.name == "query1")
{
this.OnUserQueryComplete(fqlResult.fql_result_set.
ToString());
}
else if (fqlResult.name == "query2")
{
this.OnFriendQueryComplete(fqlResult.fql_result_set.
ToString());
}
}
}
The preceding code deserves some explanation. When Facebook loads your Weather2.aspx
page, it uses the session key information for the user that is
currently logged into Facebook on the computer in which the page is
executing. Calling GetLoggedInUser returns
the User Id for that user, which is a numeric value. After you have the
User Id, you can query the Facebook database for information about that
user. In this case, two queries are required. The first query queries
information from the logged-in user's profile. In particular, the query
retrieves the name, current_location, pic_square columns from the user table. The following FQL query retrieves user information:
"SELECT name, current_location,pic_square from user WHERE uid=" + userId;
1. Finding out about your friends
The second query retrieves the name, current_location, pic_square, and uid columns from the user table for each user that is a friend of the logged in user. You query the list of friends from the uid2 column of the friend table in the Facebook database. The FQL query is a little more complex:
"SELECT name, current_location, pic_square, uid from user WHERE uid IN (SELECT
uid2 from friend WHERE uid1="+ userId + ")"
The Multiquery method of the Facebook.Rest.Fql
class batches both queries and sends them to the Facebook server. The
Facebook server returns a result set for each of the queries. The FQL
APIs return query results in XML format for storage in a DataSet object or for manual parsing. After the query results are retrieved, you can populate the user and friend data on the WeatherControl Web User Control as follows:
public class ProfileInfo
{
private string _City;
private string _State;
private string _PostalCode;
private string _ProfileImage;
private string _Name;
public string City
{
get
{
return (_City);
}
set
{
_City = value;
}
}
public string State
{
get
{
return (_State);
}
set
{
_State = value;
}
}
public string PostalCode
{
get
{
return (_PostalCode);
}
set
{
_PostalCode = value;
}
}
public string ProfileImage
{
get
{
return (_ProfileImage);
}
set
{
_ProfileImage = value;
}
}
public string Name
{
get
{
return (_Name);
}
set
{
_Name = value;
}
}
}
private void OnFriendQueryComplete(string result)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(result);
XmlNodeList userNodes = xmlDoc.GetElementsByTagName("user");
List<ProfileInfo> friends = new List<ProfileInfo>();
foreach (XmlNode node in userNodes)
{
ProfileInfo friend = new ProfileInfo();
foreach (XmlNode userNode in node.ChildNodes)
{
if (userNode.Name == "pic_square")
{
friend.ProfileImage = userNode.InnerText;
}
else if (userNode.Name == "name")
{
friend.Name = userNode.InnerText;
}
else if (userNode.Name == "current_location")
{
foreach (XmlNode locationNode in userNode.ChildNodes)
{
if (locationNode.Name == "city")
{
friend.City = locationNode.InnerText;
}
else if (locationNode.Name == "state")
{
friend.State = locationNode.InnerText;
}
else if (locationNode.Name == "zip")
{
friend.PostalCode = locationNode.
}
}
}
}
friends.Add(friend);
}
this.MyWeather.Friends = friends;
}
private void OnUserQueryComplete(string result)
{
XmlDocument xmlDoc = new XmlDocument();
string strUser = string.Empty;
string strImageUrl = string.Empty;
xmlDoc.LoadXml(result);
XmlNodeList imageNodes = xmlDoc.GetElementsByTagName("pic
if (imageNodes != null && imageNodes.Count > 0)
{
strImageUrl = imageNodes[0].InnerText;
}
XmlNodeList userNodes = xmlDoc.GetElementsByTagName("name");
if (userNodes != null && userNodes.Count > 0)
{
strUser = userNodes[0].InnerText;
}
XmlNodeList nodes = xmlDoc.GetElementsByTagName("current
string strCity = string.Empty;
string strState = string.Empty;
string strZip = string.Empty;
foreach (XmlNode node in nodes)
{
foreach (XmlNode locationNode in node.ChildNodes)
{
if (locationNode.Name == "city")
{
strCity = locationNode.InnerText;
}
else if (locationNode.Name == "zip")
{
strZip = locationNode.InnerText;
}
else if (locationNode.Name == "state")
{
strState = locationNode.InnerText;
}
}
}
if (!string.IsNullOrEmpty(strZip))
{
string strLocation = string.Empty;
if (!string.IsNullOrEmpty(strCity))
{
strLocation = strCity;
}
if (!string.IsNullOrEmpty(strState))
{
strLocation += ("," + strState);
}
this.MyWeather.CurrentLocation = strLocation;
this.MyWeather.ProfileUser = strUser;
this.MyWeather.ProfileUserImage = strImageUrl;
}
}
2. Accessing weather data for your friend's location
After you have the
profile information containing user and location information for the
logged-in user as well as that user's friends, you can get weather
information for their location in the WeatherControl.ascx.cs code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Net;
using System.Text;
using System.IO;
using System.Xml;
namespace CurrentLocalWeather
{
public partial class WeatherControl : System.Web.UI.UserControl
{
private string _Url = "http://www.google.com/ig/api?weather=";
private string _BaseUrl = "http://www.google.com";
private CurrentConditions _CurrentConditions = new CurrentConditions();
private List<ForecastConditions> _ForecastConditions = new
List<ForecastConditions>();
private ForecastInformation _ForecastInformation = new
ForecastInformation();
private string _CurrentLocation;
private string _ProfileUser;
private string _ProfileUserImage;
private List<ProfileInfo> _Friends;
public List<ProfileInfo> Friends
{
get
{
return (_Friends);
}
set
{
_Friends = value;
}
}
public string CurrentLocation
{
get
{
return (_CurrentLocation);
}
set
{
this._CurrentLocation = value;
}
}
public string ProfileUser
{
get
{
return (_ProfileUser);
}
set
{
_ProfileUser = value;
}
}
public string ProfileUserImage
{
get
{
return (_ProfileUserImage);
}
set
{
_ProfileUserImage = value;
}
}
protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
this.DropDownFriendList.DataSource = this._Friends;
this.DropDownFriendList.DataTextField = "Name";
this.DropDownFriendList.DataBind();
string actualUrl = _Url + _CurrentLocation;
this.LoadForecastData(actualUrl);
}
else
{
string actualUrl = _Url + _CurrentLocation;
this.LoadForecastData(actualUrl);
}
}
private void OnResponseReady(IAsyncResult result)
{
HttpWebRequest request = (HttpWebRequest)result.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.
EndGetResponse(result);
Encoding utf8Encoding = Encoding.UTF8;
StreamReader responseStream = new StreamReader(response.
GetResponseStream(), utf8Encoding);
string content = responseStream.ReadToEnd();
this._ForecastConditions.Clear();
BuildForecastFromXml(content);
UpdateDisplay();
}
private void BuildForecastFromXml(string xmlContent)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlContent);
XmlNodeList forecastNodes = xmlDoc.GetElementsByTagName("forecast_
information");
foreach (XmlNode node in forecastNodes)
{
foreach (XmlNode forecastNode in node.ChildNodes)
{
XmlAttributeCollection attrs = forecastNode.Attributes;
if (forecastNode.Name == "city")
{
this._ForecastInformation.City = attrs.
GetNamedItem("data").InnerText;
}
else if (forecastNode.Name == "postal_code")
{
this._ForecastInformation.PostalCode = attrs.
GetNamedItem("data").InnerText;
}
else if (forecastNode.Name == "forecast_date")
{
this._ForecastInformation.ForecastDate = attrs.
GetNamedItem("data").InnerText;
}
else if (forecastNode.Name == "current_date_time")
{
this._ForecastInformation.CurrentDateTime = attrs.
GetNamedItem("data").InnerText;
}
}
}
XmlNodeList currentConditionsNodes = xmlDoc.
GetElementsByTagName("current_conditions");
foreach (XmlNode node in currentConditionsNodes)
{
foreach (XmlNode currentNode in node.ChildNodes)
{
XmlAttributeCollection attrs = currentNode.Attributes;
if (currentNode.Name == "condition")
{
this._CurrentConditions.ConditionData = attrs.
GetNamedItem("data").InnerText;
}
else if (currentNode.Name == "temp_f")
{
this._CurrentConditions.TempF = attrs.
GetNamedItem("data").InnerText;
}
else if (currentNode.Name == "temp_c")
{
this._CurrentConditions.TempC = attrs.
GetNamedItem("data").InnerText;
}
else if (currentNode.Name == "humidity")
{
this._CurrentConditions.HumidityData = attrs.
GetNamedItem("data").InnerText;
}
else if (currentNode.Name == "wind_condition")
{
this._CurrentConditions.WindData = attrs.
GetNamedItem("data").InnerText;
}
else if (currentNode.Name == "icon")
{
this._CurrentConditions.IconData = attrs.
GetNamedItem("data").InnerText;
}
}
}
XmlNodeList forecastDataNodes = xmlDoc.
GetElementsByTagName("forecast_conditions");
foreach (XmlNode node in forecastDataNodes)
{
ForecastConditions cond = new ForecastConditions();
foreach (XmlNode forecastDataNode in node.ChildNodes)
{
XmlAttributeCollection attrs = forecastDataNode.Attributes;
if (forecastDataNode.Name == "day_of_week")
{
cond.DayOfWeek = attrs.GetNamedItem("data").InnerText;
}
else if (forecastDataNode.Name == "low")
{
cond.LowTemp = attrs.GetNamedItem("data").InnerText;
}
else if (forecastDataNode.Name == "high")
{
cond.HighTemp = attrs.GetNamedItem("data").InnerText;
}
else if (forecastDataNode.Name == "icon")
{
cond.IconData = attrs.GetNamedItem("data").InnerText;
}
else if (forecastDataNode.Name == "condition")
{
cond.ConditionData = attrs.GetNamedItem("data").
InnerText;
}
}
this._ForecastConditions.Add(cond);
}
}
private void UpdateDisplay()
{
try
{
this.ForecastLabel1.Text = this._ForecastConditions[0].DayOfWeek;
this.ForecastImage1.ImageUrl = this._BaseUrl + this._
ForecastConditions[0].IconData;
this.ForecastLabel2.Text = this._ForecastConditions[1].DayOfWeek;
this.ForecastImage2.ImageUrl = this._BaseUrl + this._
ForecastConditions[1].IconData;
this.ForecastLabel3.Text = this._ForecastConditions[2].DayOfWeek;
this.ForecastImage3.ImageUrl = this._BaseUrl + this._
ForecastConditions[2].IconData;
this.ForecastLabel4.Text = this._ForecastConditions[3].DayOfWeek;
this.ForecastImage4.ImageUrl = this._BaseUrl + this._
ForecastConditions[3].IconData;
this.ForecastTemp1.Text = this._ForecastConditions[0].HighTemp +
"/" + this._ForecastConditions[0].LowTemp;
this.ForecastTemp2.Text = this._ForecastConditions[1].HighTemp +
"/" + this._ForecastConditions[1].LowTemp;
this.ForecastTemp3.Text = this._ForecastConditions[2].HighTemp +
"/" + this._ForecastConditions[2].LowTemp;
this.ForecastTemp4.Text = this._ForecastConditions[3].HighTemp +
"/" + this._ForecastConditions[3].LowTemp;
this.CurrentTempLabel.Text = this._CurrentConditions.TempF + " F
/ " + this._CurrentConditions.TempC +" C";
this.CurrentConditionsImage.ImageUrl = _BaseUrl + this._
CurrentConditions.IconData;
this.City.Text = this._ForecastInformation.City;
this.CurrentProfileImage.ImageUrl = this._ProfileUserImage;
this.CurrentProfileName.Text = this._ProfileUser;
}
catch (System.Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
private void LoadForecastData(string url)
{
try
{
HttpWebRequest request =
(HttpWebRequest)WebRequest.Create(url);
HttpWebResponse response = (HttpWebResponse)request.
GetResponse();
Encoding utf8Encoding = Encoding.UTF8;
StreamReader responseStream = new StreamReader(response.
GetResponseStream(), utf8Encoding);
string content = responseStream.ReadToEnd();
this._ForecastConditions.Clear();
BuildForecastFromXml(content);
UpdateDisplay();
}
catch (System.Exception ex)
{
Console.WriteLine(ex.Message);
}
}
protected void DropDownFriendList_SelectedIndexChanged(object sender,
EventArgs e)
{
if (this.IsPostBack)
{
ListItem item = this.DropDownFriendList.Items[this.
DropDownFriendList.SelectedIndex];
if (item != null)
{
string userId = item.Value;
/*Now, find this user*/
IEnumerable<ProfileInfo> profile =
from friend in _Friends where friend.Name == userId
select friend;
foreach (ProfileInfo info in profile)
{
_ProfileUser = info.Name;
_ProfileUserImage = info.ProfileImage;
if (!String.IsNullOrEmpty(info.PostalCode))
{
_CurrentLocation = info.PostalCode;
}
else
{
string strLocation = string.Empty;
if (!String.IsNullOrEmpty(info.City))
{
strLocation += info.City;
}
if (!String.IsNullOrEmpty(info.State))
{
strLocation += ("," + info.State);
}
_CurrentLocation = strLocation;
}
}
}
string actualUrl = _Url + _CurrentLocation;
this.LoadForecastData(actualUrl);
}
}
}
}
Finally, you add a reference to the WeatherControl.ascx WebUserControl to your Weather2.aspx page for rendering weather data as follows:
<%@ Page Title="" Language="C#" MasterPageFile="~/Site.
Master" AutoEventWireup="true" CodeBehind="Weather2.aspx.cs"
Inherits="CurrentLocalWeather.WebForm1" %>
<%@ Register TagPrefix="AndrewMoore" TagName="Weather" Src="WeatherControl.ascx"
%>
<%@ MasterType VirtualPath="~/Site.Master" %>
<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<AndrewMoore:Weather id="MyWeather" runat="server"/>
</asp:Content>
When the application is
complete, you can select F5 to launch it from Visual Studio just like
you would any other ASP.Net application. You'll see your application
load on the Web site and then make requests to Facebook, which in turn
will call back to your Web application and request the canvas, which is the Weather2.aspx code you created. This code executes on your Web site and returns HTML to Facebook as shown in Figure 1.