Community Open Day 2012 の補足その1

Community Open Day 2012
http://cod.ms/
Community Open Day 2012 の準備 | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/3476

なところで、発表したものの、事前準備が足りない…つーか、コード自体を見せるの忘れていたので補足しておきます。
スライド自体は、

Cod2012 デバッグ講座
http://www.slideshare.net/moonmile/cod2012

なところを参照してください。概要しか書いて無くて、実際は、スレートpc へのリモートデバッグが主なところです。
開発マシンからスレートPCへリモート接続する場合は、Visual Studio から接続すればよいのですが、テストをしていくといくつか問題があったのです。

  • Visual Studio からデバッグ実行していると、サスペンドしない。
  • スレートPCへの接続は「無線LAN」なので、スピード自体に問題がでそう。

多分、サスペンドしないのはデバッグモードで動いているために、権限が desktop アプリ側にあるからだと思います。デバッグ時にサスペンドして貰っても困るし、というのもありますが。
が、実機で動かす場合、サスペンドする時、サスペンドから復帰する時、というのが metro アプリでは結構重要で、このタイミングを実機でみるのは重要かなと思ったわけです。

で、通常はローカルファイルに書き込むわけですが、metro アプリの場合は desktop 側への制限が厳しいために、

  • マイドキュメントなどのファイルアクセスに、マニフェストを変えないといけない。
  • metro アプリ内のサンドボックスに書き込むとアンインストールした時にログファイルも一緒に消えてしまう。

という欠点があります。なので、ひとつの手段として、metro アプリから HttpClient を使って開発機にログを飛ばそうという試みです。最終的には、log4net のように使えるといいんでしょうねえ。

デモで使ったサンプルコード自体は、

win8/MetroMemoPadiPadLike at master ・ moonmile/win8 ・ GitHub
https://github.com/moonmile/win8/tree/master/MetroMemoPadiPadLike

に一式があります。

■ metro アプリからログ出力

App.xaml.cs の中に次のようなログ関数を作っておきます。単純に「win8rp-pc.local」というマシンに HttpClinet を飛ばしているだけです。
本来ならば、きちんと Web REST 形式にすれば良いのですが、まあサンプルということで。
ログ自体は、WCF サービスにするときっちりと作れるのでしょうが、WCF だといちいちサービスを立ち上げないといけないので、結構面倒です。
なので、適当に GET コマンドで送れるパターンにしておきます。

[code lang=”csharp”]
public async static void DebugLog(string text)
{
string url = "http://win8rp-pc.local:8083/metro/method";
HttpClient client = new HttpClient();
try
{
HttpResponseMessage res = await client.GetAsync(url + "/" + text);
}
catch
{
}
// string response = await res.Content.ReadAsStringAsync();
}
[/code]

サーバーに接続できない場合もあるので、try-catch は必須ですね。また、このパターンだといちいち new HttpClient をしているので、本当は別に privete 変数で保持したほうがいいと思います。

[code lang=”csharp”]
private void OnSuspending(object sender, SuspendingEventArgs e)
{
App.DebugLog("OnSuspending");
var deferral = e.SuspendingOperation.GetDeferral();
//TODO: Save application state and stop any background activity
deferral.Complete();
}
[/code]

metro アプリ自体のサスペンドは、App.OnSuspending になるので、ここに仕込みます。

■回転時にログを出力する

スレートPCを回転させたときのログ出力は、MainPage.xml.cs の Current_SizeChanged メソッドになります。
このイベントは、あらかじめ Window.Current.SizeChanged += Current_SizeChanged; のように回転イベントに仕込んでおきます。

[code lang=”csharp”]
private void Current_SizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
{
var state = Windows.UI.ViewManagement.ApplicationView.Value;
VisualStateManager.GoToState(this, state.ToString(), false);
App.DebugLog("Current_SizeChanged " + state.ToString());
}
[/code]

こうすると、実機を回転した時にログが出力されます。

■簡易ログサーバー

metro アプリからログ受信をするためのサーバーを作ります。
HttpListener クラスという目的そのままのクラスがあるので、これを利用します。これは non-blocking で動くので、background スレッドを作らなくてよいので、非常に便利です。

[code lang=”csharp”]
namespace MetroLogServer
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

HttpListener listener;

private void button1_Click(object sender, EventArgs e)
{
string url = "http://*:8083/metro/";
// 開始
listener = new HttpListener();
listener.Prefixes.Add(url);

listener.Start();
listBox1.Items.Add("サーバー開始");
listener.BeginGetContext(ListenerCallback, listener);
}

public void ListenerCallback(IAsyncResult result)
{
// HttpListener listener = (HttpListener)result.AsyncState;
HttpListenerContext context;
try
{
context = listener.EndGetContext(result);
}
catch
{
// stop メソッドで例外が発生するので、対処
return;
}
// var content = listener.GetContext();
var req = context.Request;
var url = req.RawUrl;
var res = context.Response;

string text = url.Replace("/metro/method/", "");
text = System.Web.HttpUtility.UrlDecode(text);
listBox1.Items.Add("受信:" + text);

var output = new StreamWriter(res.OutputStream);
output.WriteLine(string.Format("called {0}", url));
output.Close();

// 次の受信の準備
listener.BeginGetContext(ListenerCallback, listener);
}

private void button2_Click(object sender, EventArgs e)
{
// 終了
listener.Stop();
listBox1.Items.Add("サーバー終了");
}
}
}
[/code]

本当は、これを説明しないと駄目だったんですけどね…なんか、いきおいデモのほうに進んでしまって、前提のコードの紹介が抜けてしまいました。時間配分は10分ごとに確認していたのですが、回転時の動作とかリモート接続とかの解説に力を入れ過ぎてしまったという感じです。

こんな風にシミュレータ上と開発機で通信もできます。

という訳で、もうちょっと cod2012 の話が続く。

カテゴリー: C#, windows 8 パーマリンク

Community Open Day 2012 の補足その1 への1件のコメント

  1. masuda のコメント:

    metro 用のシミュレータがいまひとつ(=環境を汚す)という話は、このシミュレータ内にあるフォルダ(マイコンピュータ)を見ると分かります。ファイルなどは全てシミュレータの起動元と同じになっているので、シミュレータ内で設定を変えると、開発環境の方も変わってしまうという訳ですね。ホスト名とかネットワークも共有しているので、そのあたり「シミュレータ環境内だからサンドボックスになっている」と思うと妙なことになります。
    iPhone開発をするときのシミュレータは完全にサンドボックスなので外部環境には影響を与えません。多分 Windows Phone の開発環境もそうなんだろうけど。どうせならば、Metro アプリのシミュレータもそうなってほしいなぁと。

    が、シミュレータ自体で動かすのであれば、VMPlayer などを使って、仮想マシンとして Windows 8 を立ち上げるほうが「環境を汚さない」という点では楽です。なので、別のマシンにログを HttpClient で飛ばすのは、それなりに理由があるかと。ただ、仮想環境ならば、ファイル共有をしてしまってローカルファイルに書き込むのでもいいような気もしますが、それだとマニフェストが変わってしまうということで(そのうち、なにか良いログツールが出るとは思いますが)。

コメントは停止中です。