(2012/06 追記 : 最新の ASP.NET Web API プロジェクトでは、Json.NET が含まれています。Json.NET を使用したプログラミングについては、こちら を参照してください。)
(2012/06 追記 : HttpClient を使用した最新のプログラミング手法については、こちら に掲載しました。)
環境 :
Visual Studio 2008 SP1
WCF REST Starter Kit (Preview 2)
こんにちは。
Tech Ed 2009 セッション T2-310 では、またまた時間がなく、大変失礼致しました。例により、説明割愛した箇所を補足致します。
まずは、デモでお見せした WCF REST Starter Kit によるコンシューマ実装についてです。 (ご説明した、「必要な事前設定」という点も記載します。)
その前に、コンシューマ実装の全体を少し復習しておきましょう。(この説明も、かなり駆け足になってしまいましたので。。。)
REST クライアント (コンシューマ) の実装方法 (全体)
例えば、ASP.NET においても jQuery がサポートされているため、ASP.NET MVC などビュー内で閉じた実装をおこなう場合には、こうしたライブラリを組み合わせてコンシューマ (クライアント) を構築することもできます。
MSDN マガジン : jQuery によるリッチなクライアント スクリプトについて
http://msdn.microsoft.com/ja-jp/magazine/dd453033.aspx
以下では、こうした実装方法を除き、Microsoft が提供しているテクノロジ (特に .NET 周り) を使用して REST のコンシューマを作成する数々の方法について整理しましょう。
- HttpWebRequest (または WebClient) を使用した実装
.NET で HTTP 通信のクライアントを実装する際に使用されるお馴染みの手法です。取得したデータは、XmlReader の使用、LINQ to XML を使用したクエリなどで処理することができます。
もっともオーソドックスで素直な手法ですが、この方法だと、ストリームの処理、XML の構文解析 (または、xsd を使用したクラスへのデシリアライズ処理) などを自前で実装することになります。 - ASP.NET AJAX, Microsoft AJAX Library (ASP.NET AJAX のクライアントライブラリ) のプロキシを使用した実装
JavaScript ライブラリである Microsoft AJAX Library 内で定義されている Sys.Net.WebServiceProxy などを使用して Json フォーマットのサービスと通信できます。(サーバサイドの ASP.NET AJAX ライブラリも、最終的にはこの Microsoft AJAX Library を使用しています。かなり以前に記載した記事ですが、ASP.NET AJAX の内部のメカニズムについては http://www.atmarkit.co.jp/fdotnet/aspnetajax/aspnetajax02/aspnetajax02_01.html に記載しています。)
この手法は、通信相手が Json シリアライズに限定される点だけでなく、通信相手として .NET の Web サービスやWCF サービスを強く意識して実装されているため、一般的な REST サービス (.NET 以外で構築されている RESTful サービスなど) でこの手法を使用することはむずかしくなるので注意してください。 - ADO.NET Data Services のライブラリ (フレームワーク) を使用した実装
ADO.NET Data Services のフレームワーク (内部では WCF が使用されています) を使用すると、Visual Studio から [サービス参照の追加] メニューを使用して REST サービスに接続するクライアント側のプロキシを簡単に生成できます。また、書籍「.NET 開発テクノロジ入門」で小高も記載していますが、ASP.NET AJAX 4.0 (現在は、この Preview 版が出ています) では、クライアントサイド (ブラウザ側) の JavaScript で同様の処理をおこなうこともできます。
この方法は大変便利な手法ですが、上記の WCF の場合と同様、ADO.NET Data Services を強く意識した作りになっているため、ADO.NET Data Services 以外の REST サービスとの接続向けではないので注意してください。 - Json.NET, DataContractJsonSerializer を使用した実装
.NET Framework 3.5 (Visual Studio 2008) では、Json フォーマットのデータのシリアライズを扱える DataContractJsonSerializer クラス (System.ServiceModel.Web.dll に定義) が含まれています。
このクラスは、その名の通り WCF での Json フォーマットの扱いを考慮して提供されているクラスですが (つまり、そもそも今回のようなクライアントから使うためのもの、というよりは、WCF が提供するクラスを間借りして処理するイメージです)、CodePlex で入手できる新しい Json.NET を使うと、型付けされていない任意の型の .NET オブジェクトと Json フォーマット間でのシリアライズ / デシリアライズを扱うクラスや、Json フォーマットのデータを LINQ のクエリなどで扱える LINQ to JSON など、REST サービス / コンシューマ開発で使用することを想定したいくつかの便利なクラスが含まれています。
これらは .NET のコードであるためサーバサイドで使用するアプローチですが、Silverlight で使用することで、クライアントサイド (ブラウザ側) の処理でもこれらのクラスを使用することができます。(LINQ to JSON は、既に Silverlight 2 から追加されています。)
(2012/06 追記 : Json.NET を使用した最新のプログラミング手法については、こちら に掲載しました。)
(2012/06 追記 : HttpClient を使用した最新のプログラミング手法については、こちら に掲載しました。) - HttpClient を使用した実装
セッションでご紹介した CodePlex の WCF REST Starter Kit を使用します。(WCF REST Starter Kit は、今後 Visual Studio 2010 で追加される予定です。ただし、どの機能が含まれるかは現時点では未定です。)
.NET を使った実装アプローチですが、実装方法の詳細は後述します。 - WCF の Channel を使用したアプローチ
セッションでもご説明したように、クライアント側で WCF (ChannelFactory など) を使って REST のサービスに接続することも可能です。(この場合も、同様に、.NET によるコードです。)
この実装では、- WCF の svcutil.exe ではなく ChannelFactory を使用した接続 (ただし、ClientBase<> を使用して自身でプロキシコードを作成することでプロキシを使用した接続も可能です)
– クライアント側の Contract にも UriTemplate を設定 (これを設定しないと、クライアントが URL を理解できません)
– WCF の DataContractSerializer の変わりに、XmlSerializerFormat を使用といったプログラミングになります。下記のブログに方法 (コード) が記載されていますので参考にしてください。
http://blogs.msdn.com/pedram/archive/2008/04/21/how-to-consume-rest-services-with-wcf.aspx
この手法は、通信相手が WCF である場合には非常に「美しい」手法ですが、その他の REST サービスとの相互連携には向かない点や (Contract を定義する必要がある、など)、最近主流の AtomFeed などを扱う場合などには、結局、実装技術に依存する (Atom10FeedFormatter などが返るため) などの点があることを理解しておいてください。
HttpClient (WCF REST Starter Kit) を使用した接続
この方法は見ていただくように大変扱いやすい手法ですが、まだ日本で動かしている人は少ないかもしれないので (実は下記で記載するように一部に日本語の問題があります)、手順詳細を記載します。(セッションで説明しなかった事前設定についても記載します。)
まず、このあと使用する WCF REST Starter Kit (Preview 2) の [Paste Xml As Types] メニューですが、ソースに一部不備があるため、英語版以外の Visual Studio ではこのメニュー出て来ないでしょう。ですので、現状は、以下の通り修正してから使用してください。(まだ Preview 版ですので、今後修正されるのをお待ちください。)
- %ProgramFiles%\Microsoft WCF REST\WCF REST Starter Kit Preview 2\WCF REST Starter Kit Preview 2.zip を展開します (ソースコードが展開されます)
PasteXmlAsType プロジェクトが入っているため、このプロジェクトを Visual Studio で開いて、Connect.cs の 80 行目を下記の通り修正してください。(この PasteXmlAsType プロジェクトは、本来、カスタマイズ用に提供されています。)
[現在]
CommandBarControl pasteControl = (CommandBarControl)toolsPopup.CommandBar.Controls[“Paste”];
[日本語用の Fix]
CommandBarControl pasteControl = (CommandBarControl)toolsPopup.CommandBar.Controls[“貼り付け”];
ビルドをおこない、Visual Studio をいったんすべて終了し、コンパイルされた .dll と、プロジェクト内にある PasteXmlAsType.AddIn を%MyDocuments%\Visual Studio 2008\Addins に配置します。(Addins フォルダがない場合は、新規作成してください。)
Visual Studio を起動すると、[編集] メニューの中に [Paste Xml As Types] メニューが追加されているはずです。(もし追加されない場合は、念のため、devenv.exe /resetaddin <プロジェクト> で起動してみてください。)
では、本題の、HttpClient を使用したプログラミングに入っていきましょう。
まず、REST のサービスをあらかじめ作成しておきましょう。WCF でも、ADO.NET Data Services でも、PHP や Java で構築したサービスでも、インターネット上のサービスでも何でも構いません。
クライアントとして、今回は、コンソールアプリケーションのプロジェクトを新規作成して、以下を参照追加します。
- %ProgramFiles%\Microsoft WCF REST\WCF REST Starter Kit Preview 2\Assemblies 下
- Microsft.Http.dll
- Microsoft.Http.Extensions.dll
以下の名前空間を追加します。(2 つ目も必ず入れておいてください)
using Microsoft.Http;
using System.Xml.Serialization;
接続先の REST のデータをブラウザなどで表示し (下図)、そのソース (XML) をコピーします。
そして、Visual Studio の上記クライアントプロジェクト上で、メニュー [Paste Xml As Type] を選択して貼り付けます。
この「貼り付け」をおこなうと、素敵なことに、XML のデータがシリアライズ可能なクラスのコードとしてソースコード上に貼り付けられます。
例えば、上図の XML の場合、生成されるソースコードは以下の通りになります。
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "2.0.50727.4016")][System.Diagnostics.DebuggerStepThroughAttribute()][System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)][System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]public partial class OrderItems{private OrderItemsOrderItem[] orderItemField;[System.Xml.Serialization.XmlElementAttribute("OrderItem")]public OrderItemsOrderItem[] OrderItem{get { return this.orderItemField; }set { this.orderItemField = value; }}}[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "2.0.50727.4016")][System.Diagnostics.DebuggerStepThroughAttribute()][System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]public partial class OrderItemsOrderItem{private byte idField;private string nameField;private ushort valueField;public byte id{get { return this.idField; }set { this.idField = value; }}public string name{get { return this.nameField; }set { this.nameField = value; }}public ushort value{get { return this.valueField; }set { this.valueField = value; }}}
このコードですが、.xsd なしでコード生成されているため、ある程度予測に基づいて生成される点に注意してください。例えば、本来文字列を返している要素でも、たまたま int 型しか返していない場合には int 型に設定されているかもしれません。ですので、生成された型などをチェックし、必要に応じて修正しておきましょう。(要は、.xsd でクラス生成を実行する手間を省いてくれている、と考えるべきでしょう。)
さいごに、生成されたコードにあわせて、下記の通り Main のコードを作成してみましょう。
static void Main(string[] args){HttpClient client = new HttpClient();HttpResponseMessage res = client.Get(@"http://localhost:25631/Service1.svc/orders");OrderItems items = res.Content.ReadAsXmlSerializable<OrderItems>();foreach (OrderItemsOrderItem item in items.OrderItem){Console.WriteLine(item.name);}Console.ReadLine();}
このように、デシリアライズ (逆シリアライズ) の手間も省き、GET、POST などの Verb もメソッドとしてそのまま呼び出せるため、意味的にわかりやすくクライアントを構築することができます。
ADO.NET Data Services のサービスについても、同様の手法でアクセスできます。
以下はそのサンプルですが、Data Services が返すフィードの構造を多少理解しておく必要があるという点に注意しておいてください。(Data Services が返すフィードでは、データは Content の中に XML として含まれています。)
static void Main(string[] args){HttpClient client = new HttpClient();HttpResponseMessage res = client.Get(@"http://localhost:9583/MatsuDataService.svc/TypeAInvoice");feed feeds = res.Content.ReadAsXmlSerializable<feed>();foreach (feedEntry entry in feeds.entry){Console.WriteLine(entry.content.properties.name);}Console.ReadLine();}
上述した Json.NET が .NET 上で Json を扱える汎用的な (実装技術などに依存しない) 仕組みであるのに対して、この HttpClient は、POX など XML 形式のリソースを汎用的に扱える .NET の仕組みであると整理しておくと良いでしょう。
なお、HttpClient は、現在 (Preview 2 では)、残念ながら Silverlight に未対応ですが、今後の対応状況などについては Silverlight Web Services チームブログをウォッチしておくと良いでしょう。
Silverlight Web Service チームブログ :
http://blogs.msdn.com/silverlightws/
WCF REST Starter Kit は、セミナーでも説明したように Visual Studio 2010 で標準で含まれる予定です。(ただし、どの機能が含まれるかは現時点では未定です。)
Categories: Uncategorized