TwtMyCard was down after some brief problems handling the new geo-location features in Twitter. This is what I get for using someone else’s Twitter library :)
While it was down I added some caching and other performance improvements. It’s at least 50% faster to send business cards. Maybe even 51%.
I also added the oomph plug-in to the app based on a suggestion from Karsten Januszewski. If you had IE with oomph installed previously, you saw a little icon in the upper left to bring out a microformat overlay. Now TwtMyCard has the oomph plug-in embedded so all browsers can get the same microformat goodness.
If you have features you’d like to see added, use the feedback tab on the site. This weekend we may make some upgrades to support web finger.
It’s almost time for the long awaited release of the Facebook Developer Toolkit 3.0, the most awesomest release of the toolkit to date. The new version has great support for ASP.NET, ASP.NET MVC, Silverlight, WinForms, WPF and basically any place you can run .NET. Ryan Powers and I worked on adding MVC support last week. (actually Ryan did all the coding, I just advised). We are going to build out more samples because that seems to have been a slight problem in previous versions.
So getting started with a Facebook ASP.NET MVC FBML canvas application.
First create a new app in Facebook. For a simple example you only need to go to the canvas section and set the “Canvas Page URL” and “Canvas Callback URL” and “Render Method” to FBML. I named my app “FdtMvcSample”.
Save your Application Secret and API Key from the Basic section somewhere. You’ll need to put those in your web.config later. Now you can setup a new MVC project in Visual Studio. We’ll call it “FdtMvcSample”.
In your web.config add in your secret and API key:
1: <appSettings>
2: <add key="Secret" value="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"/>
3: <add key="ApiKey" value="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"/>
4: </appSettings>
For development of Fbml canvas apps it’s easiest to use IIS and put your machine in the DMZ or port forward. I use gotdns.com for dynamic DNS and set my callback Url to be my dynamic DNS name / IIS virtual directory name.
You’ll need to configure your MVC project to use IIS instead of the local dev server so Facebook can call back to it. Just make sure your virtual directory name matches the callback URL directory.
In your MVC project you also need to add a reference to the Facebook.dll and Facebook.Web.Mvc.dll.
In my sample I removed most of the template items from the project. To connect with Facebook, we’ll focus on the HomeController.cs:
1: [HandleError]
2: public class HomeController : Controller
3: {
4: private const string REQUIRED_PERMISSIONS = "read_stream,publish_stream";
5:
6: public ActionResult Index()
7: {
8: var api = this.GetApi();
9: ViewData["userId"] = api.Session.UserId;
10: return View();
11:
12: }
13:
14: //ApiKey & Secret in web.config
15: [FacebookAuthorization(IsFbml = true)]
16: public ActionResult Friends()
17: {
18: var api = this.GetApi();
19: var friends = api.Friends.GetUserObjects();
20:
21: return View(friends);
22: }
23:
24: [FacebookAuthorization(IsFbml = true, RequiredPermissions = REQUIRED_PERMISSIONS)]
25: public ActionResult Stream()
26: {
27: var api = this.GetApi();
28: var stream_data = api.Stream.Get(null, null, null, null);
29:
30: return View(stream_data.posts.stream_post);
31: }
32: }
33: }
For MVC, we added attributes to control authentication. You can specify if it’s Fbml or iFrame or required permissions (and API key / secret if you don’t put them in the web.config) In the above code, the Index action is our public landing page and requires no authentication. The Friends action requires authentication to get the user’s friends’ names and the Stream action requires read_stream and publish_stream permission. The attribute runs before you action and redirects to the Facebook app authorization screen if needed and then redirects back to the action. One thing to note, adding permissions like that requires us to check which permissions are already granted and redirect to the prompt permission screen. Since that requires a call to Facebook each time the action is called, it would be best to get all the permissions granted on some initial landing page. Plus the user can get that out of the way upfront. If you need page specific permissions, then it would be best to use the Fbml fb:prompt-permission in your view before those actions are called. This method is fine also, but just be aware of the impact.
On the controller we added an extension method to retrieve the Api object for making making Facebook calls based on the users current Facebook session. (You can optionally pass in the key/secret if they are not in the web.config)
In this simple example, I’m just passing the list of friends as the model to bind to the view.
1: <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
2: Inherits="System.Web.Mvc.ViewPage<IList<user>>" %>
3:
4: <asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
5: <h2>Friends</h2>
6: <ul>
7: <% foreach (user u in Model)
8: { %>
9: <li><%= u.name %></li>
10: <% }%>
11: </ul>
12: </asp:Content>
and in the master page I have some simple Fbml with a helper for generating the tabs.
1: <%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>
2: <%@ Import Namespace="FdtMvcSample.Helpers" %>
3: <div id="header">
4: <fb:tabs>
5: <%= Fbml.TabItem("Home", "Index", "Home", this.ViewContext) %>
6: <%= Fbml.TabItem("Friends", "Friends", "Home", this.ViewContext) %>
7: <%= Fbml.TabItem("Stream", "Stream", "Home", this.ViewContext) %>
8: </fb:tabs>
9: </div>
10: <div id="main_content">
11: <asp:ContentPlaceHolder ID="MainContent" runat="server" />
12: </div>
13: <div id="footer">
14: </div>
The tab helper could most likely be more elegant. I just threw that in there to see how we’d do FBML helpers. We discussed making a full set of FBML helpers but that would be a significant effort and I’m not how much they are needed.
So that’s all the code needed to build a simple Facebook ASP.NET MVC FBML canvas application.
You can download the code here. I put the full source of the required FDT components, but after the 3.0 release you can just use the new binaries.
If you would like to see a more complex example or have questions, just post in the forums.
I played around with Wave when I got access to the developer sandbox but quickly lost interest. The technology is cool, but I have no idea what the hell is going on in a Wave. Usability wise I think it’s like MySpace with a slightly less obnoxious UI. Once there are more than 5 people in a Wave and 10+ messages it’s nigh impossible to follow. With the recent launch of the non-sandbox, I thought I’d try again. Performance seems better now at least. Even in Chrome it felt sluggish and Chrome normally rips through Javascript. I think IE8 would just die on that much Javascript – IE8: “Hey, look, this is too much code for me to process and it’s going to be awhile, how about you just check out this web slice instead? Have you heard of Accelerators? I can pop up one of those for you”
So Silverlight and Wave. Maybe it doesn’t make sense to put Silverlight in a Wave, but there are still some things you could do in SL better than HTML5 + JS. Plus I like the irony of having Silverlight in Google’s flagship RIA example. SilverWave is a managed wrapper around the Google Wave gadget APIs so you can code something like:
1: private void TestWaveAPIs()
2: {
3: txtIsInWaveContainer.Text = WaveManager.Wave.IsInWaveContainer().ToString();
4: var viewer = WaveManager.Wave.GetViewer();
5: txtViewer.Text = viewer.ToString();
6: txtHost.Text = WaveManager.Wave.GetHost().ToString();
7: txtGetParticipantById.Text = WaveManager.Wave.GetParticipantById(viewer.Id).ToString();
8: txtParticipants.ItemsSource = WaveManager.Wave.GetParticipants();
9: txtIsPlayback.Text = WaveManager.Wave.IsPlayback().ToString();
10: txtGetTime.Text = WaveManager.Wave.GetTime().ToLocalTime().ToString();
11: txtState.Text = WaveManager.Wave.State.ToString();
12: }
Everything is strongly typed so you can do things like bind to a participant object. The WaveManger class handles all the HTML bridging and callbacks for events like wave state updated. It’s pretty simple and you can get the code here http://code.google.com/p/silverwave/ along with some more instructions. The cross domain stuff seems a little flakey though. Silverlight was loading fine on Saturday for me, then it seems to break. I think the problem is hosting the xap on a non-ssl domain.
When it works, the sample on code.google.com looks like the above.
I still have no ideas for an actual Silverlight gadget in a Wave because I have no idea what I’d use Wave for or what a good gadget in Wave would do. This was just to tide me over until I can further Microsoftize Wave with a wave bot in Azure. Sadly bots only work on app engine for the moment.
If you want to contribute to the code let me know. As of right now I implemented all the wave methods, but there are probably some other useful things that could be added.