WCF Data Servicesの新機能、リクエストパイプラインをご紹介します。(2/24に実施されたTechDaysセッションのフォローアップも兼ねています)
また以下のトピックに関しては1)の記事を参照してください。 ■名称の変更 ■新バージョン ■更新モジュール(開発環境)
■リクエストパイプライン データサービスのパイプライン処理のイベントが解放されました。例えば、サービスのリクエスト処理の直前などに処理を挟むことが可能です。開発チームのBlogにはこの機能の目的について以下のように書いてあります。
The goal of exposing our processing pipeline is to allow services further transparency into a data service such that a service author can do things such as setting HTTP response cache headers, wrapping interceptor processing and data service request processing in a single transaction, etc. (超意訳) サービスの作者が、HTTPレスポンスのキャッシュヘッダーのセッティングとかとか、出来るようにしたいんだよね。
では、実際に処理を記述してみたいと思います。 まず、典型的な使用方法としては、以下のように、カスタムプロバイダ作成の中で、処理を挟む形になるはずです。(Boldの部分)
public object GetService(Type serviceType) { if (serviceType == typeof(IDataServiceMetadataProvider)) return metadata; else if (serviceType == typeof(IDataServiceQueryProvider)) { this.ProcessingPipeline.ProcessingRequest += new EventHandler<DataServiceProcessingPipelineEventArgs> (ProcessingPipeline_ProcessingRequest); return query; } else return null; }
void ProcessingPipeline_ProcessingRequest(object sender, DataServiceProcessingPipelineEventArgs e) { throw new NotImplementedException(); }
ここでは、イベントハンドラになにも書いてありませんので、エラーが発生するだけですが、ここに何らかの処理(開発チームのゴールならキャッシュ関係など)を書きます。 また、指定できるイベントの種類は以下になります。 http://msdn.microsoft.com/en-us/library/system.data.services.dataserviceprocessingpipeline_events.aspx
カスタムプロバイダだけで使用するだけではなく、Entity Providerでも似たようなことをするための手軽な手法の一つとして、DataService<T>のOnStartProcessingRequestがあります。リクエスト処理前にコールされるメソッドです。純粋なリクエストパイプライン処理とは異なりますが、これで実装をしてみます。
public class pubsService : DataService< pubsEntities > { public static void InitializeService(DataServiceConfiguration config) { config.SetEntitySetAccessRule("*", EntitySetRights.All); config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2; }
protected override void OnStartProcessingRequest (ProcessRequestArgs args) { base.OnStartProcessingRequest(args); string method = HttpContext.Current.Request.HttpMethod.ToUpper(); if (method == "GET") { HttpContext context = HttpContext.Current; HttpCachePolicy c = HttpContext.Current.Response.Cache; c.SetExpires(HttpContext.Current.Timestamp.AddSeconds(20)); c.SetCacheability(HttpCacheability.Public); c.SetValidUntilExpires(true); c.VaryByHeaders["Accept-Language"] = true; } } }
普通に作成したDataServiceにBold部分を追加しただけです。 開発チームがいうようにキャッシュヘッダーに手を加えています。ここでは、Languageの設定ごとに20秒キャッシュを保つような設定です。 ちなみに、この方法は以下を参考にしています。(こんなのもCodeRecipeの逆引きにあるといいですよね・・・) 方法 - HTTP ヘッダーを使用してページのバージョンをキャッシュする
では、実行してみます。以下のように、適当ににクエリーしてみます。 http://localhost:3049/pubsService.svc/jobs そうすると、赤枠あたりに時間が表示されていると思いますが、 F5キーなどで再リクエストしても20秒はキャッシュが使用されて時刻が変化しないのがわかります。( 上記のBoldを除いた通常のリクエストで確認すれば、この時刻は毎回変更されています。)