ブラウザに出力される HTML や API の出力などのレスポンスを、サーバー側で取得したい場合がたまにある。
ASP.NET (not MVC) でこれを行う方法はいくつかある。
加工目的でなくても、Stream.Write に出力内容が入ってくるので、その内容を MemoryStream 等に入れればレスポンスをキャプチャできる。
[キャプチャ用フィルタクラス実装例]
デメリットは、キャプチャしたデータにアクセスできる Page イベント(オーバーライド可能メソッドも含む)が無いこと。
つまり、Page ライフサイクル内にキャプチャしたデータを処理するタイミングはなく、上記コードのようにフィルタクラスの Flush ないし Close 時に処理を挟むことしかできない。
そして、Page ライフサイクルから外れるため、セッションに保存できない。
余談だが、Response.Filter は ASP.NET MVC にも存在しているので、同じことができる。
→ そのままキャプチャ可能。
[Page.Render のキャプチャ実装例]
この方法は、Page ライフサイクル内の処理なので、セッションに保存できる。
デメリットは、オーバーライドなので、フィルタクラスのように機能分離できないこと。
ASP.NET (not MVC) でこれを行う方法はいくつかある。
Response.Filter を使う方法
Response.Filter にフィルタクラス (Stream 継承) を設定すると、レスポンスを出力前に加工することができる。加工目的でなくても、Stream.Write に出力内容が入ってくるので、その内容を MemoryStream 等に入れればレスポンスをキャプチャできる。
[キャプチャ用フィルタクラス実装例]
public class CaptureStream : Stream
{
public CaptureStream(Stream targetStream)
{
_targetStream = targetStream;
Captured = new MemoryStream();
}
private readonly Stream _targetStream;
public MemoryStream Captured { get; private set; }
public override void Write(byte[] buffer, int offset, int count)
{
// 対象のストリームとメモリに書込み
_targetStream.Write(buffer, offset, count);
Captured.Write(buffer, offset, count);
}
public override void Flush()
{
_targetStream.Flush();
// ここで Captured に対する処理を行う (ログ出力など)
// OnFlush イベントを用意するとベター
}
public override void Close()
{
_targetStream.Close();
Captured.Close();
base.Close();
// Captured に対する処理は、ここでも可能
// MemoryStream は Close してもバッファは残るので ToArray などが可能
}
// 残りのオーバーライドは適宜実装
}
//---- 使用例 ----//
// Page クラス内の OnLoad などで
Response.Filter = new CaptureStream(Response.Filter);
デメリットは、キャプチャしたデータにアクセスできる Page イベント(オーバーライド可能メソッドも含む)が無いこと。
つまり、Page ライフサイクル内にキャプチャしたデータを処理するタイミングはなく、上記コードのようにフィルタクラスの Flush ないし Close 時に処理を挟むことしかできない。
そして、Page ライフサイクルから外れるため、セッションに保存できない。
余談だが、Response.Filter は ASP.NET MVC にも存在しているので、同じことができる。
Page.Render を使う方法
Page.Render をオーバーライドすると、出力されるレスポンスデータにアクセスできる。→ そのままキャプチャ可能。
[Page.Render のキャプチャ実装例]
protected override void Render(HtmlTextWriter writer)
{
string captured = null;
using( var sw = new StringWriter() )
using( var htw = new HtmlTextWriter(sw) ){
// メモリ内にレスポンス出力
base.Render(htw);
captured = sw.ToString();
// 文字列化したレスポンスをブラウザに出力
writer.Write(captured);
}
// captured に対する処理を行う
}
この方法は、Page ライフサイクル内の処理なので、セッションに保存できる。
デメリットは、オーバーライドなので、フィルタクラスのように機能分離できないこと。
0 件のコメント:
コメントを投稿