前回、Glimpseのタイムラインにカスタム項目を追加する方法をテキトウなサンプルで説明しましたが、今回は少し実用的なコードを書いてみたいと思います。
外部Webサービスを並列で複数回呼び出すような処理があったとします。
public class HomeController : Controller今回はWebサービスの代わりにランダムに1~5秒 Sleepするashxを用意します。
{
public async TaskIndex()
{
// 並列に処理
var messages = await Task.WhenAll(Enumerable.Range(1, 5).Select(async i =>
{
using (var hc = new HttpClient())
{
// 外部Webサービスを呼び出してるつもり
var url = string.Format("http://localhost/Sleep.ashx?name={0}", i);
return await hc.GetStringAsync(url);
}
}).ToArray());
return View(messages);
}
}
public class Sleep : IHttpHandler
{
private static readonly Random random = new Random();
public void ProcessRequest(HttpContext context)
{
var sleepTime = random.Next(1000, 5000);
Thread.Sleep(sleepTime);
context.Response.ContentType = "text/plain";
context.Response.Write(string.Format("{0}: I slept {1} millisecond.", context.Request["name"], sleepTime));
}
public bool IsReusable
{
get { return false; }
}
}
ここでGlimpseのタイムラインに表示したいのは外部Webサービスの呼び出し処理。どうやってGlimpseと連携するか…そう、もちろんHttpClientのDelegatingHandlerを使います。
class GlimpseTimelineHandlerInspector : IInspectorFactoryとか作ったほうが良いかもしれんが、今回はシンプルにIInspectorからGlimpseTimelineHandlerのstatic変数にMessageBrokerとTimerStrategyを渡します。
{
public void Setup(IInspectorContext context)
{
GlimpseTimelineHandler.MessageBroker = context.MessageBroker;
GlimpseTimelineHandler.TimerStrategy = context.TimerStrategy;
}
}
class GlimpseTimelineHandler : DelegatingHandler
{
internal static IMessageBroker MessageBroker;
internal static FuncTimerStrategy;
public GlimpseTimelineHandler()
: base(new HttpClientHandler())
{
}
public GlimpseTimelineHandler(HttpMessageHandler innerHandler)
: base(innerHandler)
{
}
protected override async TaskSendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var timer = TimerStrategy();
var offset = timer.Point().Offset;
var result = await base.SendAsync(request, cancellationToken);
var timerResult = timer.Stop(offset);
MessageBroker.Publish(
new TimelineMessage()
.AsTimelineMessage(request.RequestUri.PathAndQuery, new TimelineCategoryItem("HttpClient", "#ff0000", "#ff0000"))
.AsTimedMessage(timerResult));
return result;
}
}
後はSendAsyncの前後に処理を加えて、ControllerのHttpClient生成時にハンドラーを指定するだけ。
using (var hc = new HttpClient(new GlimpseTimelineHandler()))
{
ちゃんと並列で処理されているのが視覚的に確認できますね。