This is a preview of a quick app I built for Windows Phone 7 to remotely control a PowerPoint presentation from a WP7 device.
The app consists of a PowerPoint add-in that hosts a WCF service. The add-in creates a ribbon menu item to connect to the phone. Clicking “Connect to Phone” sends a push notification to the phone via the Microsoft Push Notification Service. The phone then sends a request to the WCF service hosted in PowerPoint to request data about the presentation along with URIs for the slides images that the add-in saves out as thumbnails. It’s definitely easier to build office add-ins with VS2010 and Office 2010.

On the phone you can use a swipe gesture or the buttons to change slides . It also includes a timer and displays the notes for the slide. Here is video of the application controlling a presentation.
[ higher quality video]
I have several other applications in the works that have a similar model of WCF services and push notifications. One is for remotely controlling media center (or streaming media center content to the phone) and the other is a collection of browser add-ins that push links to the phone and hyperlinks phone numbers to enable dialing through the phone from your desktop.
Motion is a key part of WP7 application development. Without motion, the WP7 UI is just a bunch of text. Not nearly as exciting. To delight users, you can add some transitions between pages. The sample app includes some storyboards to animate between two pages. Other people have noted that you can just use the transitioning content control form the SIlverlight toolkit. Peter Torr also had a nice animating frame control in his mix demo code (his blog has some other great code samples for WP7 app dev). I took some of those concepts and the code from the TransitioningContentControl to make a new animating frame control.
In this prototype, the frame takes a snapshot of the old content and the new content using writeable bitmaps and animates the snapshots and then replaces those with the actual page. The benefit is smoother animation on pages with lots of controls. Otherwise, if you have a large panorama, it might not animate that cleanly. Like the other solutions based on the TransitioningContentControl, you can centralize all the animations in one place and not have to handle them on each individual page. Peter’s code also had a nice snippet for choosing the animation based on the navigation direction so you could just have a forward / backward animation and not have to do anything on each page.
You could also probably add some more advanced transitions using pixel shaders or make an default no transition state if you wanted to have some specific animation on a page where individual controls transitioned out differently like some of the WP7 shell apps.
Sample Code – 100% guaranteed to work on my emulator
At some point in the future it will be awesome when you can just tell your computer what to do and it does it - without typing to help those of us with a blistering 11 WPM hunk and peck technique. Siri, a mobile digital assistant using speech recognition was voted best tech at SXSW. I don’t know about that one. Although, I'm sure it will get better when Apple rebuilds it and bundles on iPhone 5. So how would you do that on WP7? There have been some videos floating around showing Bing with some voice control so obviously the phone has speech recognition. So what options are there:
- System.Speech? Not included in WP7/SL
- Nuance software like Siri? No WP7/SL version yet.
- Invoking the SAPI dlls on the phone? No automation factory in WP7 SL.
- Web services using System.Speech and mic on the phone? YES!
The last one was my least favorite but that works for now.
I built a quick sample app to show how to do text-to-speech and speech recognition on WP7.
@eklimczak will not be happy with the developer designed UI.
In this sample there is web service with provides access to the system.speech APIs in .NET. Basically it’s just passing around byte arrays. On the phone it’s using the XNA audio frameworks to play the text-to-speech stream and to record using the microphone. The code is pretty simple and you can download from the link at the end of this post. The only things to note are adjusting the WCF config to handle larger byte uploads and the Microphone API is a little weird with that 1 second buffer. It would be nice if you could just to mic.start and mic.end which would return an array of bytes instead of managing your own stream inside the buffer ready callback.
Couple of downsides to this approach:
- Recoding from the phone has some static. Could be my code or the my mic is bad / not calibrated right.
- Having to make web service calls instead of local access is not ideal (Microsoft, please add an API for the SAPI dlls) Although in the context of an app like Siri it’s not so bad since you need to do web service lookups to get data back
- Speech recognition quality really depends on either a) a limited grammar set like that pizza grammar in the sample or b) training the recognizer. For the latter it would be annoying to have users train the system. Using the System.Speech stuff you’d have to have a profile for each user.
So until Microsoft adds some speech client APIs on the phone or Nuance releases a wp7 product, this is a decent workaround. In the future I’d like to build something similar to Siri. I shall call it Iris in homage. I’m a big fan of mobile speech apps because frankly it’s just not safe to Google while driving.
Since some of my designer co-workers have been posting UI sketches for WP7, I’d like to start posting some code prototypes for things I try out on the phone. That will probably last 2 weeks, but for the moment I have like 10 posts in the queue.
Sample Code – 100% guaranteed to work on my emulator
With the iPad, e-reader and slate PC craze, I thought I’d put together some thoughts on a Microsoft tablet device that is not the Courier. Since the content is rather long I made it a word doc - Microsoft Tablet Thoughts. I have separate thoughts on the Courier concept videos that have been released, but I’ll save those for another post.
I use Json all the time, but I feel like it’s super annoying in .NET. Typically I’d call some web service that returns Json. In .NET it seems like the best thing to is to define a data contract and use the DataContractSerializer:
[DataContract]
public class Person
{
[DataMember]
public string FirstName { get; set; }
[DataMember]
public string LastName { get; set; }
}
then to deserialize whatever string of Json I got back.
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
public static Person DeserializeToPerson( string jsonString )
{
using( MemoryStream ms = new MemoryStream( Encoding.Unicode.GetBytes( jsonString ) ) )
{
DataContractJsonSerializer serializer =
new DataContractJsonSerializer( typeof( Person ) );
return ( Person )serializer.ReadObject( ms );
}
}
Feels like a lot of code and I need to define the data contract beforehand which seems a little unnecessary given the dynamic nature of web services and Json. Things like the the memory stream reader and getting bytes off the string are brutal. Why can’t i just pass a string to the JsonDataContractSerializer? Some things seem way more complicated in .NET than they need to be. (cref: Calling REST services in .NET)
What I’d like is something closer to Python.
import simplejson as json
person = json.loads(jsonString)
print person.FirstName
That is pretty easy.
With .NET there are some options like:
System.Json
var data = JsonObject.Load(dataStream);
Console.Writeline(data["FirstName"])
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
This is pretty close to what I want. The problem is having to cast sub items to things like JsonArray and what not. Secondly, System.Json only works in Silverlight so i can’t use in a web project or desktop app.
Next option is one of the Json libraries like Json.Net. Not that I mind using any 3rd party DLLs, I just think parsing Json is fairly common if you are calling a rest web service and it should be in the framework, maybe I’m the only one that uses json all the time instead of XML but I’d rather use Lotus Notes everyday than parse XML and you know I hates the Lotus Notes.
This site has an interesting approach: http://blog.petegoo.com/archive/2009/10/27/using-json.net-to-eval-json-into-a-dynamic-variable-in.aspx
2 problems for me. I still need to reference Json.Net and there is that ridiculous looking code to convert to Expando object. I just don’t feel comfortable dropping that blob in my code.
Ideally Json parsing would be something similar but handled in the framework:
dynamic person = JsonObject.Load(jsonString)
Console.Writeline(person.FirstName)
That makes me happy. No pre-defining a contract and something in the framework that can take a string of Json and return back a dynamic object. There is so much stuff in the .NET framework, why can’t there be useful helpers that do common tasks like this.
I could totally be missing simpler solutions so feel free to chime in if I’m just an idiot and missing something obvious.
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
I feel like an idiot for not realizing this sooner, but if you have the Surface touchpack for Win7, you can reference those Microsoft.Surface.Touchpack dlls in your Surface app, remove the regular Surface references and change the namespaces and voila, your Surface app runs on Win 7. How did I not know this sooner? That seems fairly awesome to me. Surface apps running on the 3m 10-touch capacitive screen are fantastic.
Here are things I’ve been thinking about lately in regards to mobile advertising.
- Mobile advertising seems really underdeveloped. Maybe in part because it’s difficult to tailor ads to various devices and it’s easy to push the standard banner ad inventory or just punt on originality and buy Google ad words. (side note – who actually clicks on google ads? how does this make money for anyone? they seem so worthless)
- Local advertising also seems fairly weak. What replaces local business ads in local papers once they all die out? It doesn’t seem effective for those businesses to buy google ad words. The geographic targeting seems limited and again, who clicks on those ads. There seems to be room for someone to come in and dominate advertising on the local level similar to what google did with online ads in general. Make it super easy and cheap for local businesses to display ads to people that are within a given radius of their business.
- My ideal mobile advertising scenario is close to what Foursquare has done. I check-in at one venue and it alerts me of specials nearby. Although it’s pretty basic in Foursquare. It seems like it could be way more targeted. I check-in at a bar and it could present offers for drink specials at the bar next door. I love the market that could develop for bidding on what gets displayed when you check-in at certain venues. (Side note – I really want to see sponsored badges on Foursquare seems like a great revenue model. Bonus points if the foursquare app handles mobile payments to track actually getting those badges. Pay for 10 lattes with the foursqaure app, get the latte lover badge)
Ad words and banner ads just seem lazy. Want to target rich people? put a banner ad on forbes. Want to target people who like to ski? buy an ad word for “ski”
Here is what I want in ads:
- Contextual relevant – This is the whole reason facebook ads are worthless. Just because I like books by Michael Chabon, doesn’t mean I want to see an for his book. I probably already have it and most likely I was just browsing someone’s drunken party pics so I was too distracted to notice the ad anyway.
- Engaging not just distracting – There are a lot of talented agencies out there, do something good. Make me want to experience the ad instead of just clogging up the intertubes and my screen with your 120x240 animated gif.
- Demographically relevant – I like that Hulu let’s me choose. I’d rather watch the Smirnof ad than the trailer for the new Sex & the City movie. (Bonus points to Hulu for recognizing that if you show me a 10 second ad instead of 3 mins, I will actually pay attention because it’s not enough time for me to leave the room)
- Geographically focused – I see ads for Sonic on TV sometimes. I want that slushy and tater tots shown. There is no Sonic in San Francisco. That makes me sad. This shouldn’t happen.
- Value Added – Mint does this well. I don’t mind seeing credit card or bank ads because they are presented in a helpful manner and again are contextually relevant. The same ad for a “no limits platinum joie de vivre” card shown on espn.com just pisses me off and ad block is going to boot it off my screen
Mobile advertising seems like it could knock all these out. I’m out shopping, I check-in at the Extra Big & Tall show me an ad for a sale on husky fleece pants at Old Navy next door. Maybe include multiple product photos or a little video. You can even scan the ad when i purchase said husky fleece pants to complete the feedback loop. Contextually relevant – I’m shopping, Engaging – some multi-media action, Demographically relevant – I’m a big guy who like comfy pants, Geographically focused – It’s for the store next door and it adds value – I saved some money or you sold me on something I didn’t think I even needed.
Is this too much to ask for? I submit no. Stop wasting time on this pennies per billion impression non-sense. Advertisers should be able to get much higher ROI on ads and I shouldn’t have to be inundated with crap. Ads are always going to be a reality, let's just make them not suck so much.
I’m thinking I’ll just start blogging the random ideas I have. Maybe they are good and i will eventually do it or maybe someone else will and I reap the benefits or maybe they suck and nothing happens. Either way, I get a +1 on my blogging stats.
I love my kindle and I think the demise of e-Ink in favor of reading on a tablets is overrated. The Kindle app store seemed like an obvious idea. Amazon clearly needs to grow the device and lots of people are unwilling to pay $200+ for a device that “just reads books” Not that there is anything wrong with that. Plus they can charge other people for apps without actually having to think of new uses for the Kindle themselves. Well played Amazon.
So idea #1. Facebook on the Kindle. Not original right? I don’t want a Facebook client because I rarely use Facebook anymore. The one really useful thing I like about Facebook is Facebook Connect. I really just want my list of friends and their data. I want the Kindle Facebook app to prompt me for a review after I finish a book and post that to Facebook. Then I want to be able to browse books my friends liked and click to buy. I read a fair amount of books and I’m always interested in recommendations. There are bunch of social book sites out there, but I hate having to enter stuff manually. The Kindle knows when I finish a book so I’d like to just take care of it then automagically. Cross posting the review to Amazon would be nice because I value the ratings on there, but I don’t have “friends” on Amazon so there isn’t an easy way to see what they recommend.
I have no idea what the SDK allows though. It would be great if there was some OnBookCompleted event that you could attach apps to. Also it’s Java and the thought of using Java again makes Kevin the Coder cower in fear. Maybe someone can get JRuby or Jython running on there.
That or it could just tweet the books I read automatically because you really can’t overshare enough on Twitter.
It’s been awhile since I’ve used Azure. The new storage libraries are a welcome addition. As a better diagnostic framework and inter-role communication. In a previous Azure project, I wanted to use ASP.NET caching on the web role, but that breaks down if you start to run multiple instances. With inter-role communication it seems like you could use caching on the server as long as you notify the other instances of updates to the cache. I wrote a little prototype to do that. It’s fairly basic and I haven’t tested it on a real deployment or benchmarked etc. Basically this may just be a terrible way of doing things.
First I defined a contract for the cache messages:
1: using System.Collections.Generic;
2: using System.ServiceModel;
3:
4: namespace MvcWebRole1.Caching
5: {
6: /// <summary>
7: /// Defines the contract for the cache service.
8: /// </summary>
9: [ServiceContract]
10: public interface ICacheService
11: {
12: [OperationContract(IsOneWay = true)]
13: void Insert(string key, object value);
14:
15: [OperationContract(IsOneWay = true)]
16: void Remove(string key);
17: }
18: }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
Next I implemented the service for that contract.
1: using System;
2: using System.Web;
3: using System.Diagnostics;
4: using System.Linq;
5: using System.ServiceModel;
6: using System.Threading;
7: using Microsoft.WindowsAzure.Diagnostics;
8: using Microsoft.WindowsAzure.ServiceRuntime;
9:
10: namespace MvcWebRole1.Caching
11: {
12: /// <summary>
13: /// Implementation of the WCF cache service.
14: /// </summary>
15: [ServiceBehavior(
16: InstanceContextMode = InstanceContextMode.Single,
17: ConcurrencyMode = ConcurrencyMode.Multiple,
18: #if DEBUG
19: IncludeExceptionDetailInFaults = true,
20: #else
21: IncludeExceptionDetailInFaults = false,
22: #endif
23: AddressFilterMode = AddressFilterMode.Any)]
24: public class CacheService : ICacheService
25: {
26: public void Insert(string key, object value)
27: {
28: HttpRuntime.Cache.Insert(key, value);
29: Trace.TraceInformation(String.Format("Added: {0} to key: {1} from broadcast", value, key));
30: }
31:
32: public void Remove(string key)
33: {
34: HttpRuntime.Cache.Remove(key);
35: Trace.TraceInformation(String.Format("Removed key: {0} from broadcast", key));
36: }
37: }
38: }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
That handles the inserts / deletes the cached items when one instance broadcasts a cache update.
The next bit of code is used to cache on one instance and then broadcast that info out to the other roles.
1: using System;
2: using System.Diagnostics;
3: using System.Linq;
4: using System.ServiceModel;
5: using System.Threading;
6: using System.Web;
7: using Microsoft.WindowsAzure.Diagnostics;
8: using Microsoft.WindowsAzure.ServiceRuntime;
9:
10: namespace MvcWebRole1.Caching
11: {
12: public class SynchedCache
13: {
14: private enum BroadcastType
15: {
16: Insert,
17: Remove
18: }
19:
20: public static void Insert(string key, object value)
21: {
22: HttpRuntime.Cache.Insert(key, value);
23: Trace.TraceInformation(String.Format("Added: {0} to key: {1}", value, key));
24: BroadcastCacheUpdate(BroadcastType.Insert, new object[] {key, value});
25: }
26:
27: public static void Remove(string key)
28: {
29: HttpRuntime.Cache.Remove(key);
30: Trace.TraceInformation(String.Format("Removed key: {0}", key));
31: BroadcastCacheUpdate(BroadcastType.Remove, new object[] { key });
32: }
33:
34: public static object Get(string key)
35: {
36: return HttpRuntime.Cache.Get(key);
37: }
38:
39: private static void BroadcastCacheUpdate(BroadcastType type, params object[] args)
40: {
41: // iterate over all instances of the internal endpoint except the current role - no need to notify itself
42: var current = RoleEnvironment.CurrentRoleInstance;
43: var endPoints = current.Role.Instances.Where(instance => instance != current)
44: .Select(instance => instance.InstanceEndpoints["InternalHttpIn"]);
45:
46: foreach (var ep in endPoints)
47: {
48: EndpointAddress address =
49: new EndpointAddress(String.Format("http://{0}/InternalHttpIn", ep.IPEndpoint));
50: ICacheService client = WebRole.Factory.CreateChannel(address);
51:
52: try
53: {
54: string key = args[0].ToString();
55:
56: switch (type)
57: {
58: case BroadcastType.Insert:
59: client.Insert(key, args[1]);
60: break;
61:
62: case BroadcastType.Remove:
63: client.Remove(key);
64: break;
65: }
66:
67: ((ICommunicationObject)client).Close();
68: }
69: catch (TimeoutException timeoutException)
70: {
71: Trace.TraceError("Unable to notify web role instance '{0}'. The service operation timed out. {1}",
72: ep.RoleInstance.Id, timeoutException.Message);
73: ((ICommunicationObject)client).Abort();
74: }
75: catch (CommunicationException communicationException)
76: {
77: Trace.TraceError("Unable to notify web role instance '{0}'. There was a communication problem. {1} - {2}",
78: ep.RoleInstance.Id, communicationException.Message, communicationException.StackTrace);
79: ((ICommunicationObject)client).Abort();
80: }
81: }
82: }
83: }
84: }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
Finally in your page you can perform operations on the cache like so.
SynchedCache.Insert(key, DateTime.Now.ToString());.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
That call will then notify all the other web roles running. Of course running AppFabric Caching on Azure would be a much better solution once available, but the inter-role communication is still nice to have for other stuff.
Sorry for the slow response for everyone that messaged me. I didn’t think anyone would actually twitter/facebook message/email me about the app so I wasn’t really ready to release for general usage. Then I respond to some people to let them try it, doesn’t work and then they leave negative reviews on Facebook. Awesome, thanks. Anyway, there is a new version here - http://www.facebook.com/apps/application.php?id=130989934307 If you installed a previous one, just uninstall it. Please read the README in the zip file.
If this doesn’t work for people, I’m giving up. I only built this app to enter into the code7contest and I lost to an app that arguably uses no Win7 features, an old demo app from some competitor and something called “Win7 in my truck” Truly a devastating blow to my motivation to ever touch this code again.
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.
So FB7 was our fallback Code7 contest application. It’s a teaser. Our second entry is going to be epic. At Clarity we really like SketchFlow, but there are some things that would make it cooler I think. When working in a group we usually just draw on a whiteboard to map out the application flow. It’s not as easy to have a collaborative session sitting at PC and using Blend.
Our plan for the second entry is to build a large multi-touch display to put up like a whiteboard. Using your fingers like markers you can draw UI elements like windows, buttons, text, etc. The app will then recognize certain gestures. For example, you draw a really large rectangle and the app assumes you want a window. It converts that to a window. If you draw a smaller rectangle inside of the window, it’ll convert it to a control where you can hold two fingers on it to bring up a fly out menu and convert to a textbox or button. Small rectangles are converted to checkboxes and small circles, radio buttons.
Here is the first prototype of the gesture recognition for controls.
In future versions we’re adding a marker drawn style, text recognition to convert labels/titles to hand drawn font, flow recognition (draw an arrow from a button to another window to link the two), network support for remote multi-user action, manipulation to resize controls and then try to work out a way to get this into SketchFlow. The basic idea is that it’s a simple, collaborative first step before touching up in SketchFlow. I’ll post some more prototypes next week as we finish it up for the contest.
I was recently using the Facebook Desktop Notifications app for OSX. Pretty cool & useful app. The shortcut layout reminded me of the Win7 jump lists and I wanted to build something for the Code 7 contest. Since I was also doing some work on the Facebook Developer Toolkit (version 3.0 is awesome), this seemed like a nice app to build. Here is what I have so far:
Jump list shortcuts to Facebook pages and new messages / notifications
The jump list provides quick access to your latest messages, notifications and general Facebook pages.
Progress indicator when polling Facebook and unread message/notification count overlay
It was nice to bust out my old school GDI drawing skills to render the little number on the overlay icon.
Toast when new messages / notifications arrive
The toast message fades in and out for about 3 seconds when something new arrives. FB7 polls Facebook every 5 mins for new items. If you only have one new item it will just display the subject or title or snippet.
Global keyboard shortcut to update status
Defaults to ctrl+alt+space, but you can change it to anything. The window pops up with a little blur animation.
You can also attach videos or photos via drag and drop or by clicking to browse your Win7 libraries.
Settings screen
You can toggle to Facebook Lite mode so all jump lists shortcuts link to the equivalent Facebook Lite page.
Custom thumbnail to show current profile photo & status
Here is a video of the application in action.
It probably would have made more sense to make an application that runs in the tray, but I wanted to experiment with some of the new Win 7 shell integration features. I’m fairly sure I violated every UI guideline in the Win 7 shell integration guide and also most of Facebook’s terms by using their icons / logos. Also, it’s just a notification app, you can’t view your news feed from inside the app – the idea was just to port the OSX Desktop Notification app to Win 7.
Win7 has definitely grown on me. As a developer I wasn’t particularly excited about some of the shell integration points, but I think you can add some pretty nice features to your app with them. As an end user, Win7 is definitely a big improvement on Vista. Feels faster, has some nice UI tweaks and is overall really stable.
If you are interested in trying out the application to help test, email me at kmarshall at claritycon.com or send me a message on Twitter (@ksmarshall) or on Facebook
More Posts
Next page »