Wednesday, June 20, 2007

Friend Photosaver for Facebook

By now everybody who knows what Facebook is, knows they announced an open platform for integrating with it. Interestingly enough Microsoft was a launch partner of theirs so there is also a shared source .NET API layer available. We decided to jump on the opportunity and published SoapBox for Facebook. Chris mentioned this in his announcement blog earlier.

But, as with anything that goes to production, adding cool features quickly turned into fixing uncool bugs, scope discussions, planning sessions, and then it became work.

I had a bit of a realization yesterday. I hadn't written code for the sheer fun of it in a really long time. Don't get me wrong, I love the stuff I do (almost) every day. We're coding cutting edge stuff here and it's a blast. But, I wanted to do something for me! So I wrote a screensaver.

Strange, huh? The guy that writes blogs on memory management, async programming, and other maddening things decided to hack together a screensaver. You'll just have to get over the shock of it all... Research was done, scope was decided, fingers flew. A few hours later, I had a screensaver! At 2am I decided on its name (probably a bad idea), Friend Photosaver for Facebook, whipped up an installer and submitted the app to Facebook. Catchy isn't it? Yeeeah. Anyway, though the name stinks, I think it's a pretty cool screensaver.

It aggregates the list of all your photos with all of the photos of your friends, and picks them at random. It then stuffs the photo in a random spot on the screen where it will be visible. Right now it only displays on the primary screen. Secondary screens are blank. Here's a little preview:

Screen Saver

If you're a Facebook user you can login and install my screensaver. The rest of you... well, this is pretty useless. But you should be on Facebook too. Oh, and (shameless plug), don't forget to use SoapBox for Facebook. :)

Friday, June 8, 2007

Simpler isn't always better - AsyncOperationsManager

AsyncOperationManager... die!

We have a new invitation system coming out soon for SoapBox Communicator and I was doing a little premature optimization, err, I mean, capacity planning. :) I set about to perform the simple task (or so I thought) of sending all of our email based invitations asynchronously. The architecture of the system is pretty simple. We have an ASP.NET 2.0 web site that you use inside SoapBox for sending invitations to your friends. The web site talks to an internal web service. The web service talks to a database. It's a pretty classic nTier design, with one exception. All layers are asynchronous.

The UI uses asynchronous ASP.NET pages and RegisterAsyncTask to make the call to the EnqueueEmailInvites web service. The web service uses asynchronous web methods and reads from/writes to our database using the asynchronous data methods in SqlClient.

Async Web Method

[WebMethod]
public IAsyncResult BeginEnqueueEmailInvites(EmailInvitation invite, AsyncCallback callback, object state)
{
return InvitationFactory.BeginEnqueueEmailInvites(invite, callback, state);
}

[WebMethod]
public string[] EndEnqueueEmailInvites(IAsyncResult ar)
{
return InvitationFactory.EndEnqueueEmailInvites(ar);
}
Factory Calling DAL

public static IAsyncResult BeginEnqueueEmailInvites(EmailInvitation invite,

AsyncCallback callback, object state)
{
InviteEmailAsyncState myAs = new InviteEmailAsyncState();
myAs.Invitation = invite;
InviteEmailAsyncResult myAR = new InviteEmailAsyncResult(myAs, callback, state);

int emailInviteId = invite.Mutual ? GetInvitationTypeId(Constants.InviteTypeEmailMutual) :

GetInvitationTypeId(Constants.InviteTypeEmail);
string csvAddresses = string.Join(",", new List<string>(invite.Addresses).ToArray());

Data.Invitations.BeginCreateReadInvitation(emailInviteId, invite.FromJid, invite.FromName, invite.Subject, invite.UserBodyPlain, string.Empty, csvAddresses, EmailInvitationCreatedCallback, myAR);

return myAR;
}

I write a lot of asynchronous code. A lot. I'm a bit of an asynchronous I/O zealot. In fact, I've had an article on the shelf called "Asyncify your code" for months now. l I just haven't got the sample code written for it yet. Anyway, my experience has led me to a simple conclusion: I hate the AsyncOperationManager.

Maybe it's because I write a lot of asynchronous code, or maybe just because people tend to Mistake Familiarity with Superiority, but whatever the reasoning, I can't stand it. The AsyncOperationManager is used all over the .NET 2.0 framework where you see calls ending in "Async", even though you probably don't even know it. One such instance that rubbed me the wrong way yesterday (and into this morning) is the SmtpClient. Don't get me wrong, the SmtpClient is a great improvement over the old CDO based classes, but the Async support leaves something to be desired.

First off, you can't call Send or SendAsync until the previous operation has completed. That means if you're sending out more than one email in succession you're going to need to do your own queueing. So I said to myself "Ok, this is easy, I'll rip out the loop, register an eventhandler for SendCompleted, and pass a Queue through as state to SendAsync." This led me to the next problem.

The asynchronous web method called the asynchronous data method, which led to a callback. Inside of this callback I grabbed some info from the data reader result and composed the MailMessage. I created a SmtpClient, registered for the SendCompleted event kicked off the first SendAsync, and completed the asynchronus web method. The mail sent great, but my SendCompleted event handler was never called.

Apparently, if you make an async call there is the potential that the completed event handler you registered will never get called. Yep. You can call SendAsync, and the SendCompleted event will never be raised. I admit, the circumstances this happened in were kind of abnormal, but still. That just shouldn't happen.

After a little reflectoring it was apparent this had something to do with the SynchronizationContext at the time of the call used by the AsyncOperationManager inside of the SmtpClient. I got a litte cross-eyed looking through the code in reflector so I gave up my hunt for the exact answer. My workaround: Call ThreadPool.QueueUserWorkItem and create the SmtpClient and call SendAsync inside of that callback. This gets you the generic SynchronizationContext that doesn't have anything weird associated with it, just plain ole async delegates. If someone has a better solution, please let me know.

The Hack

if (messagesToSend.Count > 0)
{
//this seems strange, but we queue up the creation of the SmtpClient to a threadpool thread.
//the synchronization context seems to become invalid when we complete the async web method call
//and we don't want to wait for the emails to go out to complete the web service call.

System.Threading.ThreadPool.QueueUserWorkItem(StartSendingEmailCallback, new object[] { myAr.MyAsyncState.Invitation, messagesToSend });
}

I have a plea to all framework designers out there. Have the decency to give me the good ole IAsyncResult based async pattern without all that extra AsyncOperationManager baggage! I don't want to have to worry about all that. I'm a big boy. I can handle my own synchronization, and I like it that way.

About the Author

Wow, you made it to the bottom! That means we're destined to be life long friends. Follow Me on Twitter.

I am an entrepreneur and hacker. I'm a Cofounder at RealCrowd. Most recently I was CTO at Hive7, a social gaming startup that sold to Playdom and then Disney. These are my stories.

You can find far too much information about me on linkedin: http://linkedin.com/in/jdconley. No, I'm not interested in an amazing Paradox DBA role in the Antarctic with an excellent culture!