Posting Status Updates To Twitter Via LinqToTwitter: Part 4, Async Operations

Asynchronous operations are all the rage these days, and for good reason: Being able to do things without waiting, or in no particular order, can often allow us to create significantly more robust and capable applications.

In traditional, synchronous programming, we are often forced to create awful hacks, moving time-consuming (or, as it usually turns out, computationally risky) operations to the end of a program’s execution chain; or sometimes, to offload some important program functionality to subprocesses, in hopes that everything will turn out well.

With async methods, we can maintain proper context and scope in our applications, but proceed with other work while we wait for slow or expensive tasks to complete.

Asynchronous operations are at the heart of LinqToTwitter. That’s largely because the LinqToTwitter library relies upon web requests and responses to perform its tasks, and as anyone who regularly works with HTTP-based application programming interfaces knows, there can be significant delays between when we make a web request and when — or even, if — we receive a response.

However, a lot of code out there (especially code written prior to Visual Studio 2012, when .NET introduced asynchronous operations) simply isn’t written with async in mind. Sure, we could refactor all our legacy code to operate async where appropriate; but more likely, it’s actually better to simply treat tweeting a status as another synchronous step. (Recognizing, of course, that we will need to deal with slow responses and non-responses from the Twitter REST API.)

No, not "a sink"; async. Photo via Pixabay, in the public domain.
No, not “a sink”; async. Photo via Pixabay, in the public domain.

A Quick-And-Dirty Overview Of Async And Await

This is a brief explainer of how .NET goes about performing asynchronous tasks via the async and await keywords. If you don’t care, and just want to know how to execute async tasks in sync code, skip this.

In .NET, there are two keywords related to the asynchronous execution of a method: async and await.

Async marks a method as having an indeterminate period of time to complete its work. Await sets the point at which an async method must return to the result of an asynchronous task.

Let’s consider a workflow in which sending a tweet is only part of the work that needs to be done.

Suppose you’re in charge of recording scores for a local Little League. These scores are shown on a website, and they are also sent as new tweets from the league’s Twitter account, as soon as the scores are final.

We can easily accomplish both these needs by building an ASP.NET website that pulls data from a SQL Server database. This website can have an administration page, into which scorekeepers can enter data to automatically create box scores. When the scorekeepers mark the game as final, our admin section can both create the final box score for the game, and tweet out that result, with a link to the box score.

In this scenario, we might want the tweeting of the final score to operate asynchronously from the processing of the box score; that is, we don’t want to wait for the tweet to go through, before we create the website’s box score for the game.

If that was the case, our code to conduct these steps might well look like this:

using System;
using System.Threading.Tasks;
using LinqToTwitter;
using System.Data.SqlClient;

namespace linq2twitter_demo {
	public class BaseballGame {
		public int Id { get; set; }
		public DateTime GameDate { get; set; }
		public string HomeTeamName { get; set; }
		public int HomeTeamScore { get; set; }
		public string AwayTeamName { get; set; }
		public int AwayTeamScore { get; set; }
	}

	class Program {
		static void Main() {
			//we will come back to this
		}
		
		public async void BoxScore() {
			var game = new BaseballGame {
				Id = 100001,
				GameDate = new DateTime(2015, 9, 1),
				HomeTeamName = "Astros",
				HomeTeamScore = 7,
				AwayTeamName = "Yankees",
				AwayTeamScore = 3
			};
			
			var auth = new SingleUserAuthorizer
			{
				CredentialStore = new SingleUserInMemoryCredentialStore
				{
					ConsumerKey = "your consumer KEY from part 1",
					ConsumerSecret = "your consumer SECRET from part 1",
					AccessToken = "your access TOKEN from part 1",
					AccessTokenSecret = "your ACCESS SECRET from part 1"
				}
			};
			
			var context = new TwitterContext(auth);
			
			Task<Status> sendTweetTask = context.TweetAsync($"FINAL: {game.HomeTeamName} {game.HomeTeamScore}, {game.AwayTeamName} {game.AwayTeamScore}");
			
			using(var conn = new SqlConnection("some-connection-string")) {
				using(var cmd = new SqlCommand($"INSERT INTO ScoresTable (Id, GameDate, HomeTeamName, HomeTeamScore, AwayTeamName, AwayTeamScore) VALUES ({game.Id}, {game.GameDate}, '{game.HomeTeamName}', {game.HomeTeamScore}, '{game.AwayTeamName}', {game.AwayTeamScore}", conn) {
					conn.Open();
					cmd.ExecuteNonQuery();
					Console.WriteLine("Game result saved to database.");
				}
			}
			
			var tweetStatus = await sendTweetTask;

			if(tweetStatus != null) {
				Console.WriteLine($"Tweet sent. Id: {tweetStatus.StatusID}");
			}
			else {
				Console.WriteLine("Tweet was not sent.");
			}
		}
	}
}

This code as a Github Gist: https://gist.github.com/dougvdotcom/18ff796068ae7623a06b

Line 21 uses the async keyword to indicate that this method will operate asynchronously.

Line 44 is where we instruct the BoxScore method to go ahead and send the tweet. For this purpose, we use the Task class, indicating that this operation (Task) is expected to receive a Status object back as a result of calling the TweetAsync method.

This task is executed at the time we declare it. In other words, Line 44 is sending our tweet. However, because Task declarations of this sort work asynchronously, we can proceed with our other code, and perform the other step necessary to create a box score — recording the game results in our SQL Server database table.

However, we eventually want to know whether the tweet went through or not. And the way we determine that, in LinqToTwitter, is to see if we got a null Status back after making our TweetAsync call.

So on Line 54, we assign the value of tweetStatus, which will be a Status object, to be the result of sendTweetTask; that is, it’s the end result of Line 44.

That’s what the await keyword does; it tells the program that it cannot proceed with further code execution until Line 44 is done with its task.

Lines 56-61 then tell us the result of our effort to tweet.

In other words, given the structure of this method, we are stating that our primary concern is to record the box score in the database.

We want to send the tweet, too; because it is probably going to take a while to complete, we do that first, asynchronously. While LinqToTwitter works on sending the tweet, we insert our database record. Once that’s done, we check to see if the tweet went through.

We called the tweet action first; but we can proceed with our database code while we wait for Twitter to respond, and come back to the tweet after we’ve saved the record.

No doubt many of you would note than I could have written the database code with async methods, too. But I am trying to demonstrate how asynchronous operations work around synchronous code, so that is why I did not use async database calls.
The old-school, analog means of making async calls. Photo via Pixabay, in the public domain.
The old-school, analog means of making async calls. Photo via Pixabay, in the public domain.

Calling Async Methods From Sync Code

Fortunately, .NET recognizes that often, we will need to use asynchronous operations within code that must execute synchronously.

To do that, we use two Task class methods: Run and Wait.

The Run method uses a lambda expression (a.k.a. delegate, a.k.a. anonymous function) to execute an async method; the Wait method pauses our synchronous code until that async method has completed its task.

static void Main() {
	Console.WriteLine("Program started.");
	//execute the async task ...
	var t = Task.Run(() => { BoxScore() });
	//and wait for it to finish
	t.Wait();
	//this code executes after the task is complete
	Console.WriteLine("Program complete.");
	Console.Read();
}
It’s not strictly necessary to use the Wait method, if you don’t need to wait for an operation’s results. However, not waiting can cause unexpected, usually undesirable (and often, unacceptable) results.

For example, I could remove Line 22, above. Since Task.Run (at Line 20) immediately invokes the BoxScore method, and the BoxScore method is void, in theory I don’t need to wait for it to complete before moving on to the next thing. In theory.

In this case, not waiting would probably be OK, because I call Console.Read at Line 25, which keeps the program running until someone presses a key. As a result, it’s probable that the task will complete before someone presses a key.

However … if someone pressed a key, before the BoxScore method has completed its work, then I could well run into trouble.

For example, if it takes a few seconds to establish a database connection, that’s plenty of time for someone to come along and press a key, because the program will have reported itself completed (Line 24). But it’s not done, and since the program exits before inserting the score record, that part of the workflow will not happen.

The tweet request would have been sent through; whether it succeeds or not doesn’t depend on receiving a response from Twitter, so abandoning the program early doesn’t affect our tweet. But the database command would not have completed, and we would be none the wiser, because we exited the program.

So what’s the lesson? Always wait for tasks to complete before exiting your program. In this case, the call to Wait at Line 22 does just that.

Which brings us back to the BoxScore method, and why I wrote it to be void.

We can get objects and primitives back from asynchronous task methods. It is also possible to cancel an async task before it is complete, via a CancellationToken.

All of this is as complicated as it sounds. So my method was written as a void, so that I could have the best of both worlds: Reduce the code to be as much like synchronous code as I can, while still receiving the benefit of async methods.

Note that we can also run several asynchronous tasks at once and await the results of all tasks, too.

Looking back at the code to tweet multiple images, in Part 3 of this walkthrough:

var imageUploadTasks = 
     new List<Task<Media>> 
     {
          context.UploadMediaAsync(File.ReadAllBytes(@"c:\path\to\image1.jpg")),
          context.UploadMediaAsync(File.ReadAllBytes(@"c:\path\to\image2.png")),
          context.UploadMediaAsync(File.ReadAllBytes(@"c:\path\to\image3.jpg")),
          context.UploadMediaAsync(File.ReadAllBytes(@"c:\path\to\image4.gif"))
     };
 
await Task.WhenAll(imageUploadTasks);

… Line 35’s use of the WhenAll method tells our program that it needs to wait for all the tasks in imageUploadTasks to complete, before it proceeds to do anything else.

That’s it for this series. If you have questions, feel free to post them in the comments, and I’ll do my best to answer them.

I distribute code under the GNU GPL. See Copyright & Attribution for details.

All links in this post on delicious: https://delicious.com/dougvdotcom/posting-status-updates-to-twitter-via-linqtotwitter-part-4-async-operations

Photo via Pixabay, in pubic domain.
The thumbnail / featured image photo for this post comes via Pixabay, in pubic domain.

6 Comments

Leave a Reply

  • Check out the Commenting Guidelines before commenting, please!
  • Want to share code? Please put it into a GitHub Gist, CodePen or pastebin and link to that in your comment.
  • Just have a line or two of markup? Wrap them in an appropriate SyntaxHighlighter Evolved shortcode for your programming language, please!