読者です 読者をやめる 読者になる 読者になる

yamamoWorks

.NET技術を中心に気まぐれに更新していきます

GlimpseのタイムラインにHttpClientの処理を表示する

.NET Glimpse Tips

前回、Glimpseのタイムラインにカスタム項目を追加する方法をテキトウなサンプルで説明しましたが、今回は少し実用的なコードを書いてみたいと思います。

外部Webサービスを並列で複数回呼び出すような処理があったとします。

public class HomeController : Controller
{
public async Task Index()
{
// 並列に処理
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);
}
}
今回はWebサービスの代わりにランダムに1~5秒 Sleepするashxを用意します。
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 : IInspector
{
public void Setup(IInspectorContext context)
{
GlimpseTimelineHandler.MessageBroker = context.MessageBroker;
GlimpseTimelineHandler.TimerStrategy = context.TimerStrategy;
}
}

class GlimpseTimelineHandler : DelegatingHandler
{
internal static IMessageBroker MessageBroker;
internal static Func TimerStrategy;

public GlimpseTimelineHandler()
: base(new HttpClientHandler())
{
}

public GlimpseTimelineHandler(HttpMessageHandler innerHandler)
: base(innerHandler)
{
}

protected override async Task SendAsync(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;
}
}
Factoryとか作ったほうが良いかもしれんが、今回はシンプルにIInspectorからGlimpseTimelineHandlerのstatic変数にMessageBrokerとTimerStrategyを渡します。

後はSendAsyncの前後に処理を加えて、ControllerのHttpClient生成時にハンドラーを指定するだけ。
using (var hc = new HttpClient(new GlimpseTimelineHandler()))
{

ちゃんと並列で処理されているのが視覚的に確認できますね。