Facebook - how to run a FQL query

by Andrei Hetel 12. December 2009 16:17

Better think twice before starting a Facebook application using AP.NET - it's PHP world there. That could change in the future because I could see some C# example in Facebook wiki, which is a big step forward I suppose. More than this, in the glorious day when I finally manage to integrate some Facebook functionality into Ysabel, Facebook Developer Toolkit released version 3.0 (all my code is based on 2.0 - and people are complaining about backward compatibility) - that really made my day!

According with the pages that I read about ASP.NET and Facebook it's best to choose an IFRAME application type and use master pages. Not 100% if it's the best strategy, but this is what I've done.

Anyway, it took me a couple of hours to figure out how to run a FQL query, and after that to do something with the result, but it's finally working. I was surprised that only couple of lines of code are needed.

A working piece of code looks like this:

 

Dim fbAPI As new facebook.API
Dim query As String
Dim xmlDR As String
Dim ds As DataSet

fbAPI.ApplicationKey = "your application key"
fbAPI.Secret = "your secret key"

query = "select uid, name from user where uid in (select uid2 from friend where uid1=" & your_Facebook ID & ")"

xmlDR = fbAPI.fql.query(query)
ds = New DataSet()
ds.ReadXml(New StringReader(xmlDR), XmlReadMode.InferSchema)

Dataset returned contains 2 datatables, in the second datatable is the data you have requested (complete list of your friends according to the above query).

Simple isn't it? Happy coding.

 

Web services - returning custom objects

by Andrei Hetel 13. November 2008 14:12

This article is focused on web services, more exactly about the way you can return a custom object into your client application (in my case a windows mobile application). The easiest way is to use a simple example. On web service project let's create a simple class with only 2 properties CastleId, CastleName:

 

<Serializable()> _
Public Class CCastle

  Private _CastleId As Int64
  Private _CastleName As String

  Public Sub New()
  End Sub
  Public Sub New(ByVal newCastleId As Int64, ByVal newCastleName As String)
    _CastleId = newCastleId
    _CastleName = newCastleName
  End Sub

  Public Property CastleId() As Int64
    Get
      Return _CastleId
    End Get
    Set(ByVal value As Int64)
      _CastleId = value
    End Set
  End Property
  Public Property CastleName() As String
    Get
      Return _CastleName.Trim
    End Get
    Set(ByVal value As String)
      _CastleName = value
    End Set
  End Property

End Class

 

Please note that the class is marked as serializable and the properties are public read/write, to be able to use it into the client application created later.

Now, let's create a collection class, also serializable:

 

<Serializable()> _
Public Class CCastleList
  Private _CastleList As List(Of CCastle)

  Public Property CastleList() As List(Of CCastle)
    Get
      Return _CastleList
    End Get
    Set(ByVal value As List(Of CCastle))
      _CastleList = value
    End Set
  End Property
End Class

 

Finally, web method:

 

<WebMethod()> _
Public Function CastleList() As CCastleList

  Dim cl As New CCastleList
  Dim myList As New List(Of CCastle)

  myList.Add(New CCastle(1, "Castle1"))
  myList.Add(New CCastle(2, "Castle2"))
  cl.CastleList = myList
  Return cl

End Function

 

That's all on the web service side. Now, let's create a client application, reference the web service and call the web method. Like this:

 

Public Sub LoadCastleList()

  Dim ws As localhost.YsaMain
  Dim cl As localhost.CCastleList
  Dim castle As localhost.CCastle

  Try
    ws = New localhost.YsaMain
    cl = ws.CastleList()

    For Each castle In cl.CastleList
      debug.writeline (castle.CastleId & " " & castle.CastleName)
    Next castle

  Catch ex As Exception
  End Try
End Sub

 

Save repeater data to CSV

by Andrei Hetel 9. September 2008 10:36

I was working recently on a web project. One of the requirements was to save the data from a repeater control (I decide to use repeater and not DataGrid because of speed) into a CSV file. Don't know if this is the best method or not, but this is the way I did it. Relevant code in ASPX page:

<table>
<asp:Repeater ID="test" runat="server" >
  <HeaderTemplate>
    <tr>
      <td>Item</td>
      <td>Count</td>
      <td>Price</td>
      <td>VAT</td>
      <td>Total</td>
    </tr>
  </HeaderTemplate>
  <ItemTemplate>
    <tr>
      <td><asp:label ID="Item" Text=<%#DataBinder.Eval(Container, "DataItem.Item")%> runat="server" /></td>
      <td><asp:label ID="Cnt" Text=<%#DataBinder.Eval(Container, "DataItem.Cnt")%> runat="server" /></td>
      <td><asp:label ID="Price" Text=<%#DataBinder.Eval(Container, "DataItem.Price")%> runat="server" /></td>
      <td><asp:label ID="VAT" Text=<%#DataBinder.Eval(Container, "DataItem.VAT")%> runat="server" /></td>
      <td><asp:label ID="Total" Text=<%#DataBinder.Eval(Container, "DataItem.Total")%> runat="server" /></td>
    </tr>
  </ItemTemplate>
</asp:Repeater>
</table>
<asp:Button id="Export" Text="Export" runat="server" />

 

We need the following class:

 

Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.IO
Imports System.Text

Public Class CCSVExport
  Private _pPage As Page = Nothing
  Private _Title As String
  Private _ColumnList As ArrayList
  Private _FName As String

  Public Sub New(ByVal pPage As Page, ByVal tit As String, ByVal fName As String, ByVal colList As ArrayList)
    _pPage = pPage
    _Title = tit
    _FName = fName
    _ColumnList = colList
  End Sub

  Public Sub ExportRepeater(ByVal rpt As Repeater)
    Dim context As System.Web.HttpContext
    Dim byteArray() As Byte

    context = System.Web.HttpContext.Current
    context.Response.Clear()
    context.Response.Buffer = True
    context.Response.ContentType = "application/vnd.ms-excel"
    context.Response.Charset = ""
    _pPage.EnableViewState = False
    context.Response.AddHeader("Content-Disposition", "attachment;filename=" & _FName & ";")
    byteArray = System.Text.Encoding.ASCII.GetBytes(BuildData(rpt).ToString)
    context.Response.BinaryWrite(byteArray)
    context.Response.End()
  End Sub

  Private Function BuildData(ByVal rpt As Repeater) As StringBuilder

    Dim ri As RepeaterItem
    Dim currentLine As String
    Dim arrayIndex As Int16
    Dim sb As New StringBuilder

    sb.AppendLine(_Title)
    For Each ri In rpt.Items

      currentLine = ""
      If ri.ItemType = ListItemType.AlternatingItem Or ri.ItemType = ListItemType.Item Then
        For arrayIndex = 0 To _ColumnList.Count - 1
          currentLine &= CType(ri.FindControl(_ColumnList.Item(arrayIndex)), Label).Text.Trim & ","
        Next arrayIndex
        sb.AppendLine(currentLine)
      End If
    Next ri
    Return sb
  End Function
End Class

 

Code in page load, just binding the repeater to a datatable:

 

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

  test.DataSource = dt
  test.DataBind()

End Sub

 

Finally, export the data:

Protected Sub Export_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Export.Click

  Dim fileTitle As String
  Dim export As CCSVExport
  Dim arrFields As ArrayList

  fileTitle = "Test"
  arrFields = New ArrayList

  arrFields.Add("Item")
  arrFields.Add("Cnt")
  arrFields.Add("Price")
  arrFields.Add("VAT")
  arrFields.Add("Total")
  export = New CCSVExport(Page, fileTitle, "test.csv", arrFields)
  export.ExportRepeater(test)
End Sub

 

Index a repeater – pretty simple

by Andrei Hetel 6. February 2008 12:45

Piece of code presented here simply add a column, not related with content of the repeater, which index current line of data.
Repeater definition:

 

<asp:Repeater id="RB" runat="server">
  <HeaderTemplate>
    <tr>
      <td align="right">#</td>
      <td>User</td>
      <td align="right">Points</td>
    </tr>
  </HeaderTemplate>
  <ItemTemplate>
    <tr>
      <td align="right"><asp:Label ID="t5" runat="server"></asp:Label></td>
      <td><%#DataBinder.Eval(Container.DataItem, "UserName")%></td>
      <td align="right"><%#DataBinder.Eval(Container.DataItem, "TotalPoints")%></td>
    </tr>
  </ItemTemplate>
</asp:Repeater>

 

In code behind, first declare a variable:

 

Private CounterOverallTop As Integer = 1

 

Don’t forget to bind your data to the repeater, something like:

RB.DataSource = … your data source RB.DataBind()

 

Following code will populate index column.

 

Protected Sub RB_ItemDataBound(ByVal sender As Object, _
                                                   ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs) _
                                                   Handles RB.ItemDataBound

  If (e.Item.ItemType = ListItemType.Item) Or _
    (e.Item.ItemType = ListItemType.AlternatingItem) Then

      DirectCast(e.Item.FindControl("t5"), Label).Text = CounterOverallTop
      CounterOverallTop += 1

  End If

End Sub