TwitterizerでUserStreamを利用する

TwitterのAPIライブラリ、Twitterizer Ver 2.3.1を使ってUserStreamを利用しようと以下のコードを書いたんです。

using System;
using System.Net;
using System.Reflection;

namespace ConsoleApplication1
{
	class Program
	{
		static void Main(string[] args)
		{
			string consumerKey = "hoge";
			string consumerSecret = "hogehoge";
			Twitterizer.OAuthTokenResponse reqToken = Twitterizer.OAuthUtility.GetRequestToken(consumerKey, consumerSecret, "oob");
			Uri uri = Twitterizer.OAuthUtility.BuildAuthorizationUri(reqToken.Token);
			System.Diagnostics.Process.Start(uri.ToString());
			Console.WriteLine("Pinコードを入力しる");
			string pinCode = Console.ReadLine();
			Twitterizer.OAuthTokenResponse accToken = Twitterizer.OAuthUtility.GetAccessToken(consumerKey, consumerSecret, reqToken.Token, pinCode);
			Twitterizer.OAuthTokens token = new Twitterizer.OAuthTokens
			{
				ConsumerKey = consumerKey,
				ConsumerSecret = consumerSecret,
				AccessToken = accToken.Token,
				AccessTokenSecret = accToken.TokenSecret
			};
			using (var twitterStream = new Twitterizer.Streaming.TwitterStream(token))
			{
				twitterStream.OnStatusReceived += (Twitterizer.TwitterStatus status) =>
				{
					Console.WriteLine(string.Format("{0}/({1})\r\n\t{2}",
						status.User.Name,
						status.User.ScreenName,
						status.Text));
				};
				twitterStream.StartUserStream();
				while (true) { }
			}
		}
	}
}

何度試しても404が返ってくる。実はこれ、ベータ版のアドレスにアクセスしてるんですよ。これがソースコード

no title

がっつりとハードコーディングされちゃっててどうにもなりません。自家ビルドして使う?嫌ですよ、そんなの。面倒じゃないですか。幸い、このStartUserStreamメソッドは短いです。じゃあStartUserStreamメソッドを呼び出してる部分のコードをURLだけ置き換えた同じ内容のコードに書き換えればいいじゃない!

以下の3行までは問題ないです。

WebRequestBuilder builder = new WebRequestBuilder(new Uri("http://betastream.twitter.com/2b/user.json"), HTTPVerb.GET, this.Tokens);
HttpWebRequest request = builder.PrepareRequest();
request.KeepAlive = true;

URLを置き換えるだけです。WebRequestBuilderクラスはpublicなので問題なく利用出来ます。引数に渡しているthis.Tokensはコンストラクタに渡したインスタンスそのものなので、こちらのスコープで保持しているものに置き換えればいいです。

問題は最後の行ですね

request.BeginGetResponse(StreamCallback, request);

引数に渡しているStreamCallbackっての、これprivateなメソッドなんですよ。これはリフレクションで取ってくることにしました。

MethodInfo method = twitterStream.GetType().GetMethod("StreamCallback",
    BindingFlags.Instance |
    BindingFlags.NonPublic);
AsyncCallback callback = (_) =>
{
    method.Invoke(twitterStream, new[] { _ });
};

リフレクションで取ってきたメソッドをInvokeするコードをAsyncCallbackデリゲートで包んであげればOKじゃんって寸法です。

で、最終的なコードがこんな感じ

using System;
using System.Net;
using System.Reflection;

namespace ConsoleApplication1
{
	class Program
	{
		static void Main(string[] args)
		{
			string consumerKey = "hoge";
			string consumerSecret = "hogehoge";
			Twitterizer.OAuthTokenResponse reqToken = Twitterizer.OAuthUtility.GetRequestToken(consumerKey, consumerSecret, "oob");
			Uri uri = Twitterizer.OAuthUtility.BuildAuthorizationUri(reqToken.Token);
			System.Diagnostics.Process.Start(uri.ToString());
			Console.WriteLine("Pinコードを入力しる");
			string pinCode = Console.ReadLine();
			Twitterizer.OAuthTokenResponse accToken =Twitterizer.OAuthUtility.GetAccessToken(consumerKey, consumerSecret, reqToken.Token, pinCode);
			Twitterizer.OAuthTokens token = new Twitterizer.OAuthTokens
			{
				ConsumerKey = consumerKey,
				ConsumerSecret = consumerSecret,
				AccessToken = accToken.Token,
				AccessTokenSecret = accToken.TokenSecret
			};
			using (var twitterStream = new Twitterizer.Streaming.TwitterStream(token))
			{
				twitterStream.OnStatusReceived += (Twitterizer.TwitterStatus status) =>
				{
					Console.WriteLine(string.Format("{0}/({1})\r\n\t{2}",
					status.User.Name,
					status.User.ScreenName,
					status.Text));
				};
				//twitterStream.StartUserStream();
				//StartUserStreamメソッドがベータ版のURLに繋いでエラーになるから
				//下記ソースの動作をURLだけ変えて実行
				//http://pm.twitterizer.net/projects/twitterizer/repository/entry/tags/twitterizer-2.3.1/Twitterizer2.Streaming/TwitterStream.cs#L138
				var builder = new Twitterizer.WebRequestBuilder(new Uri("https://userstream.twitter.com/2/user.json"), Twitterizer.HTTPVerb.GET, twitterStream.Tokens);
				HttpWebRequest request = builder.PrepareRequest();
				request.KeepAlive = true;
				MethodInfo method = twitterStream.GetType().GetMethod("StreamCallback",
					BindingFlags.Instance |
					BindingFlags.NonPublic);
				AsyncCallback callback = (_) =>
				{
					method.Invoke(twitterStream, new[] { _ });
				};
				request.BeginGetResponse(callback, request);
				while (true) { }
			}
		}
	}
}

 

これでめでたくUserStreamが使えるようになりました。ちなみにtrunkの最新のソースコードでもURLはベータ版のものがベタ書きのままでした。中の人忙しいのかな…。