あっあれ??バインド済み
今メンテナンスしているシステムでは、WebブラウザーにホストしたSilverlightからローカルコンピューターに対しソケット通信なんかをやっているわけです。必然的にクロスドメインになるので、常駐アプリでローカルポリシーサーバーを立ててあげます。
詳しくはMSDNのこちらを参照
あれ?ポリシーサーバーがバインドできない
- 今までは問題無く動作していたんだけれど、ローカルのソケットサーバーで943番ポートをバインドしようとしたらこんな例外が出た。
System.Net.Sockets.SocketException (0x80004005): アクセス許可で禁じられた方法でソケットにアクセスしようとしました。
場所 System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
場所 System.Net.Sockets.Socket.Bind(EndPoint localEP)
今まで実行できていたのになんでだろう?なにか別のサービスがポートを専有している?とおもい、おもむろにコマンドプロンプトでnetstatを実行
netstat –a –b
プロトコル ローカル アドレス 外部アドレス 状態
… 略 …
TCP 0.0.0.0:943 XXXX:0 LISTENING [XamlSpyService.exe]
… 略 …
あー、WPFで作ったアプリのXAMLを確認するのにXAML Spy入れた、確かに入れた。
こいつSilverlightのXAMLを確認するから、独自でポリシーサーバー持つのか。
XAMLを確認するなら
実行中アプリのXAMLを確認するだけなら、XAML SPYを使わなくてもSNOOPでもいいよね。デザインなんかはとても気に入っているのですが、、、さようならXaml Spy。
Silverlight5の信頼されたアプリケーションのブラウザー実行
メモ、どうも日本語資料がなかなか無いんだけれど、八巻さんの資料に載ってた。
Silverlight 5でぶり返すWPF不要論(http://www.slideshare.net/Yamaki/silverlight-5wpf)16ページあたり
というか、MSDNに日本語の記述がない。。。消え行く技術には厳しいのか。
#この記事書くまで、このサイトのカテゴリに「メモ」がなかったことに気づいた。。。
.NET関連のUserVoice
製品に反映するためにユーザーの声をあつめるサービスににUserVoiceがあります。
Microsoftで言えば、公式なフィードバックはMicrosoft Connectで受け付けていますが、UserVoiceにもMicrosoftが幾つかのフォームらを開設しています。既に役目を終えたところもあると思いますが、サラっと検索て出てきた.NET関係のUserVoiceを上げておきます。
都度追加予定…
.NET User Voice
- Silverlight Feature Suggestions
- Visual Basic Content Requests
- WCF RIA Services
- WPF Feature Suggestions
ASP.NET
SQL Server
Data Developer
Windows Phone
Windows Azure
あれ?Azureは独自にホスティングしているのかな?
- Microsoft® Codename "Dallas" Feature Voting
- SQL Azure Data Sync Feature Voting
- SQL Azure Feature Voting
- SQL Azure Reporting Feature Voting
- Windows Azure AppFabric Feature Voting
- Windows Azure Code Samples Voting
- Windows Azure Documentation Voting
- Windows Azure Feature Voting
- Windows Azure Platform Training Kit
番外
なんかUserVoiceを探してたら、こんなフィードバック募集もあった。
.NET開発者中心/Insider.NETへの読者フィードバック
ココにフィードバックすれば、@ITで記事になるのかな?
Mango Sdk BetaでMVVM Lighttoolkitを使おう
Mango Sdk Betaがでてからしばらく立ちますが、WPF/Silverlight/Windows Phoneに対応したMVVMのツールキットであるMVVM LighttoolkitもMangoに対するパッチが公開されています。
バイナリーのインストール
パッチといってもバイナリーの置き換えになるようですが、安定版の MVVM Light Toolkit V3とプレビュー版の MVVM Light Toolkit V4ともにリリースされています。それぞれ次のリンクからダウンロード出来きます。
ただ、V3とV4はアセンブリが同じ名前なので、もし同居させたいならデフォルトとは違うフォルダーにインストール擦る必要がありますが、その場合、後述のテンプレートの参照先がおかしくなってしまうので、気をつけましょう。
MVVMの通常のインストールと同じように、ダウンロード後にC:\Program Filesに解答してあげましょう。MVVM LightTool V3のインストール方法はこちら。→ MVVM Light Toolkitをインストールしてみる。
V3を利用する場合は、NuGetで次のコマンドを実行すれば、インストールの作業をしなくても利用できます。
Install-Package MvvmLight
プロジェクトテンプレートのインストール
プロジェクトテンプレートには、通常のVisual Studio用のテンプレートと、Windows Phone用のVisual Studio Express用の2つがあります。
Visual Studio用は、Visual Studioのオプション→Tools→Options→Project and Solutionsにある、User Project Locationで確認できます。
デフォルトでは、ここが指定されています。
%UserProfile%\Documents\Visual Studio 2010\Projects
テンプレートをインストールすると、MvvmLight (WP7.1) がテンプレートに追加されます。
CodeZine: Silverlightによるデスクトップアプリケーション
今回から3回に分けてブラウザー外実行です。
Silverlightによるデスクトップアプリケーション
Silverlight 4で作る新しいRIAアプリケーション(8)
http://codezine.jp/article/detail/5770
#wordpress のクイック投稿って機能を使ってみた。
VB.NETにMVVM LightToolkitのテンプレートを追加しよう
MVVM LightToolkitのVB用テンプレートがないと聞いたので、とりあえずViewModelのテンプレートを作ってみました。
Visual Studioのテンプレートを作るのは簡単です。
- もともとになるプロジェクトやファイルを作って、
- 置き換えようのパラメーターをソースに適用して、
- ウィザードからテンプレート化して、
- UserTemplateフォルダーに置く
だけ。
ということで、やってみます。
1.テンプレートのもととなるプロジェクトを作る。
まずは、テンプレートのもととなるプロジェクトを作ります。
本来のMVVM LightToolkitのプロジェクトテンプレートから作られるプロジェクトは、アセンブリの参照以外にも、MVVM LocatorやMVVM Viewなどが最初からプロジェクトに追加されていますが、今回は単にMVVM LightToolkitのアセンブリが追加され、ViewModelが一つ追加されたものを作ります。
MVVM LightToolkitに必要なアセンブリは、次の3つです。
- MVVM Light Toolkitをインストールしてみる。をもとに、セットアップしているなら、アセンブリはここにあるはずです。C:\Program Files\Laurent Bugnion (GalaSoft)\Mvvm Light Toolkit\Binaries\Silverlight4
テンプレートにする、ViewModelクラスを作成します。ViewModelBaseクラスを継承する以外は、特に記述するものもないのですが、C#のテンプレートにならってこんなクラスを追加してみました。C#ではクラスファイルには名前空間を含めますが、VBではアプリケーションレベルでは既定の名前空間を使うのが習わし?になっているので名前空間は定義していません。
Option Explicit On Option Strict On Option Infer On Imports GalaSoft.MvvmLight Public Class Class1 Inherits ViewModelBase Public Sub New() 'if (IsInDesignMode) ' ' Code runs in Blend --> create design time data. 'Else ' ' Code runs "for real": Connect to service, etc... 'End If End Sub 'Public Overrides Sub Cleanup() ' ' Clean own resources if needed ' 'MyBase.Cleanup() 'End Sub End Class
とりあえず、この状態でビルドが通ることを確認したら、テンプレートのもととなるプロジェクトの作成は終了です。
2.換えようのパラメーターをソースに適用する。
テンプレート化するアイテムは、アイテムの追加ダイアログで指定したファイル名をクラス名につけたいので、次のように修正します。
Option Explicit On Option Strict On Option Infer On Imports GalaSoft.MvvmLight Public Class $safeitemname$ Inherits ViewModelBase Public Sub New() 'if (IsInDesignMode) ' ' Code runs in Blend --> create design time data. 'Else ' ' Code runs "for real": Connect to service, etc... 'End If End Sub 'Public Overrides Sub Cleanup() ' ' Clean own resources if needed ' 'MyBase.Cleanup() 'End Sub End Class
クラス名をClass1から、定義済みテンプレート名である、$safeitemname$に変更しています。このほかのテンプレート名は、MSDNを参照してください。また、カスタムテンプレートを定義することもできます。
3.ウィザードでテンプレート化する。
テンプレートウィザードを開始するには、Visual Studioのファイル⇒テンプレートのエクスポートを実行します。
今回は、アイテムテンプレートを追加するので、ラジオボタンで項目テンプレートを選択します。
アイテムテンプレートに含むファイルを指定します。今回は先ほど修正したMVVMViewModel.vbを選択します。
このファイルが参照するアセンブリを選択します。ここでは上記の3アセンブリを参照します。
テンプレートの情報を定義してテンプレートの作成は完了です。
4.UserTemplateフォルダーに置く
テンプレートを自動的にVisual Studioにインポートを選択すると、今回作成された項目テンプレートが、下記の場所に作成され、Visual Studioに自動登録されます。
%UserProfile%\Documents\Visual Studio 2010\My Exported Templates
テンプレートを適用する。
アイテムの追加ダイアログに作成したテンプレートが表示されます。
プロジェクトのテンプレートを作る。
プロジェクトテンプレートの作り方は、基本的に項目テンプレートと同じです。
テンプレートのウィザードの最初で、プロジェクトテンプレートを選択するだけです。
テンプレートの構成
Visual Studioのテンプレートファイルは単なるZipファイルです。解凍するとテンプレートの構成を書いたvstemplateファイルと、テンプレートに含まれるファイルやアイコンが解凍されます。
このvstemplateファイルはを修正することで、アイテム追加時のカスタム動作を追加することができます。
詳細はこちら⇒プロジェクトと項目テンプレートのカスタマイズ
MVVMとはを学ぶ上でこれ以上無い資料が公開中
この前の勉強会でメッセージ通信の話をしていた @ugaya40 さんが、MVVMパターンと他のUIパターンというタイトルで資料を公開されています。なんというか、この前の勉強会の前半で僕が言いたかったことが凄まじく良くまとまっています。
MVVMってなに?MVCやMVPと何が違うの?何が嬉しいのって部分で悩んでいる方。必読です!!
MVVMパターンとイベント駆動開発、そしてMVC/MVP/PMパターンとの関係 – 何故MVVMなのか
⇒ http://ugaya40.net/wpf/mvvm-mvc-mvp-pm-eventdriven.html
ログインしているユーザー情報をもとに返却するXAPファイルを変更する。
ユーザーによって違うバージョンを提供したいという場合があります。
例えば一般ユーザーには安定しているVersion 1.0を使わせたいけれど、あるユーザーにはお試し版のVer1.1のSilverlightアプリケーションを使わせたいといった場合です。場合によっては古いアプリケーションをしばらく使わせたいといった場合も有るでしょう。
ASP.NETでどうにかしたい場合は例えば次の方法が思いつきます。
- SilverlightをホストするHTMLのobjectタグを動的に書き換える。
- ジェネリックハンドラーで動的に切り替える。
- IHttpHandlerで動的に切り替える。 2のジェネリックハンドラーで動的に切り替える方法を考えてみます。
概要
Silverlightをロードする場合、通常であればsourceパラメーターにSilverlightの配置先を指定します。
HTML側にはすべてのユーザーで同じURLを指定させ、ユーザーのセッション情報をもとにデータベースで管理しているユーザーごとのバージョンテーブルを検索し、ユーザー別に指定されたXAPファイルをダウンロードさせます。
ジェネリックハンドラーの記述
通常ASP.NETのページはASPXの拡張子で作成しますが、画像やXAPファイルなどのコンテンツファイルを動的に返したいときはASHXを利用することで余計な処理が少ない分パフォーマンスよくクライアントに折り返すことができます。
Visual Studioでジェネリックハンドラーを追加したい場合には、Visual StudioでGeneric Handlerを追加します。
ジェネリックハンドラーではどのようなコンテンツを返却するかをProcessRequestメソッドに記述します。
実際に返却するコンテンツは、ProcessRequestメソッドの引数であるHttpContextクラスのResponseプロパティーやRequestプロパティー、Sessionプロパティーをもとに値を返却します。ただし、Sessionプロパティーを利用するためには、IRequiresSessionStateインターフェイスを実装する必要があります。
using System; using System.Web; using System.IO; using System.Web.SessionState; namespace WebApplication1 { public class SilverlightVersionSelector : IHttpHandler, IRequiresSessionState { public void ProcessRequest(HttpContext context) { context.Response.ContentType = "application/xaml+xml"; // 1.QueryStringからアプリケーション名を取得する。 // var app = context.Request["xap"]; if (string.IsNullOrEmpty(app)) { context.Response.BinaryWrite(XapManager.GetDefaultXap()); } // 2.セッション情報からユーザーの情報を取得する。 if (context.Session == null || context.Session["_userContext"] == null) { context.Response.BinaryWrite(XapManager.GetBeforeAuthenticationXap(app)); return; } var userContext = context.Session["_userContext"] as UserContext; // 3.アプリケーション名とユーザー情報からユーザーに返却するXAPを決定する。 var path = context.Server.MapPath(((Func<UserContext, string, string>)((u,appName)=> { if (appName == "app1" && u.UserId == "karua") return @"\ClientBin\SilverlightApplication1.xap"; else return @"\ClientBin\SilverlightApplication2.xap"; }))(userContext, app)); // 4.XAPファイルが存在したら、XAPファイルを返却する。 if (!File.Exists(path)) { context.Response.StatusCode = 404; context.Response.End(); return; } context.Response.BinaryWrite(File.ReadAllBytes(path)); } public bool IsReusable { get { return true; } } } }
順番に見ていきましょう。
1.QueryStringからアプリケーション名を取得する。
通常であれば、Silverlightをロードする場合は次のようなHTMLでXAPファイルを指定します。
<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%"> <param name="source" value="/ClientBin/SilverlightApplication1.xap"/> <param name="onError" value="onSilverlightError" /> <param name="background" value="white" /> <param name="minRuntimeVersion" value="4.0.50401.0" /> <param name="autoUpgrade" value="true" /> </object>
今回は作成したジェネリックハンドラーを指定し、xapパラメータをもとにロードするXAPファイルを切り替えます。もしXAPパラメーターが指定されなかった場合は、既定のXAPファイルがロードされるようにしておきましょう。
<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%"> <param name="source" value="/SilverlightVersionSelector.ashx?xap=app1"/> <param name="onError" value="onSilverlightError" /> <param name="background" value="white" /> <param name="minRuntimeVersion" value="4.0.50401.0" /> <param name="autoUpgrade" value="true" /> </object>
2.セッション情報からユーザーの情報を取得する。
セッション情報から現在ログインしているユーザーの情報を取得します。ジェネリックハンドラーでセッション変数を利用する場合はIRequiresSessionStateインターフェイスを実装しないと、Session変数が取得できないので注意しましょう。ここでも取得できない場合にはログイン前のXAPファイルを返すようにしておきましょう。
3.アプリケーション名とユーザー情報からユーザーに返却するXAPを決定する。
今回のサンプルでは、単純にxapパラメーターがapp1で、セッション変数に格納されているユーザー名がkaruaだったらSilverlightApplication1.xapを、それ以外だったらSilverlightApplication2.xapを返すようにしていますが、本来でしたら、データベースなどのユーザー別の台帳のようなものを用意して検索するようにします。
4.XAPファイルが存在したら、XAPファイルを返却する。
3で取得したファイルが存在したら、ファイルの情報をバイナリーで読み出しHttpContextクラスのResponseプロパティーのBinaryWriteメソッドを使って書き出します。
MVVM を使った アプリケーション開発 -基本編-
本日(11/6)の第60回codeseek勉強会・第2回日本C#ユーザー会勉強会で使用するスライドと、サンプルアプリケーションのソリューションファイルをとりあえずアップロードしておきます。1時間枠のセッションはかなり久々なので時間配分がどうなるかが全然わかりません。まぁなるようになるかなと思いながら。。。
⇒スライド MVVMを使ったアプリケーション開発 -基礎編-
⇒Visual Studio 2010ソリューションファイル サンプルアプリ
http://cid-b17f5fcd8095628b.office.live.com/self.aspx/%e5%85%ac%e9%96%8b/MVVMSample.zip
MVVMでのServiceLocatorの導入
MVVM Lighttoolkit では、ViewModelはServiceLocatorが提供する仕組みになっています。いや、別にこれまでのエントリーのように、ServiceLocatorを使わなくても構築できるんですけれど、そうなっているからには何かしらの理由が有るはずです。。今回は、ServiceLocatorって何者よっていうのを解説してみようと思います。
ServiceLocatorとは
ServiceLocatorとは、プログラマーの代わりにクラスのインスタンスを管理してくれる子です。
通常クラスの実体が欲しければ、newキーワードでインスタンス化するわけですが、ServiceLocatorにクラスのインスタンスを管理してもらうことで、クラスの生成時に処理を割りこませたり、インスタンスを差し替えたりできるので、MVVMなどのレイヤー型のアーキテクチャーを採用しているプロジェクトとはそれなりに相性が良いです。これがもう少し進むとIoCが出てくるんですが、まぁそこまで行かなくてもいいでしょう。
インスタンスの差し替えと生成の割り込み
MVVMに限らないのですが、内部に持っているサービスクラスを差し替えたいことがあります。
例えば、作ったモジュールの単体テストをしたいんだけれど、依存している部分のせいでテストが行えなかったり、外部のWebサービスを参照していたり、参照するクラスライブラリがまだ実装していたりしない場合などです。このような場合、サービスの振る舞いをインターフェイスに抽象化して、サービスをテスト用のものに差し替えると、このような問題を回避できます。
具体的にはこんな感じです。
public class SampleViewModel: ViewModelBase { public IHelloService service { get; set; } public SampleViewModel() { } public string GetHelloMessage() { return service.GetMessage(); } } public class SampleServiceLocator { public SampleViewModel Sample { get { return new SampleViewModel { service = new HelloService(), }; } } }
この場合、HelloServiceはIHelloServiceとして抽象化されているので、例えばテスト時にはこんなクラスに差し替えてSampleViewModelのテストをすることができます。また、XAMLでクラスのインスタンスを作成する場合、引数なしコンストラクターが呼び出されるのですが、ServiceLocator側でプロパティーとして公開し、内部で引数付きのコンストラクターを呼び出すことも可能です。
単体テストが嬉しい
SampleViewModelの単体テストをしたいけれど、HelloServiceがまだ出来ていないとか、Webサービスを参照しているとか行った場合、HelloServiceの都合で、SampleViewModelがテストできないなんてことになります。ただ、サービスをインターフェイスに切りだしてあれば、単体テスト時にモック用のサービスに差し替えることでこんなふうにテストできますよね。
[TestClass] public class Tests { [TestMethod] public void TestMethod1() { var target = new SampleViewModel(); target.service = new HelloServiceMock(); var actual = target.GetHelloMessage(); Assert.AreEqual<string>("てすと", actual); } }
デザイン時に嬉しい
Silverlightでは、Blendなどで画面を編集する場合はコンストラクターでWebServiceからデータの取得などを行っているとデザイン画面が開けない。なんてことが起きるので、通常はViewModel内部で実行時の動作なのか、デザイン時の動作などかを判断し、コードを振り分けるなんてことをします。
この場合も、デザイン用のサービスをViewModelに与えることで、ViewModel内に実行時かどうかの判断を各必要がなくなります。たとえば、さっきのGetHelloMessageメソッド内部で判断しようとするとこうなるけれど、
public string GetHelloMessage() { if (DesignerProperties.IsInDesignTool) { return "でざいんようめっせーじ"; } else { service.GetMessage(); } }
これよりは、デザイン用のサービスを用意して、生成時に差し替えて、GetHelloMessageメソッド自体では単に与えられたサービスを呼び出すほうが、ifの分岐がなくなる分嬉しいですよね。
public class SampleServiceLocator { public SampleViewModel Sample { get { return new SampleViewModel { service = (DesignerProperties.IsInDesignTool) ? new DesingHelloService() : new HelloService(), }; } } }
まとめ
MVVM Lighttoolkitでは、プロジェクトテンプレートで、MVVMのプロジェクトを作ると、ServiceLocatorをApp.xamlでインスタンス化し、各XAMLページでは、このLocatorが持っている各ViewModelをバインドすることでViewModelをViewに関連付けています。
ということで、ServiceLocatorを導入することで、クラスの生成に割り込めるので、テストがしやすくなったり、ブレンドでのデザインがしやすくなるというのを確認してもらえたのではないかと思います。