Created
June 20, 2022 03:19
-
-
Save meziantou/30b602d846589b3148b4c6e82dfd487d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<HttpRequestLoggerComponent /> | |
<Router AppAssembly="@typeof(App).Assembly"> | |
<Found Context="routeData"> | |
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" /> | |
<FocusOnNavigate RouteData="@routeData" Selector="h1" /> | |
</Found> | |
<NotFound> | |
<PageTitle>Not found</PageTitle> | |
<LayoutView Layout="@typeof(MainLayout)"> | |
<p role="alert">Sorry, there's nothing at this address.</p> | |
</LayoutView> | |
</NotFound> | |
</Router> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Diagnostics; | |
using Microsoft.AspNetCore.Components; | |
using Microsoft.JSInterop; | |
namespace HttpRequestLogger | |
{ | |
public sealed class HttpRequestLoggerComponent : ComponentBase, IDisposable | |
{ | |
[Inject] | |
public IJSRuntime? JS { get; set; } | |
protected override void OnInitialized() | |
{ | |
HttpLoggerService.RequestStarted += HttpLoggerService_RequestStarted; | |
HttpLoggerService.RequestStopped += HttpLoggerService_RequestStopped; | |
} | |
private void HttpLoggerService_RequestStarted(object? sender, HttpRequestMessage e) | |
{ | |
if (JS != null) | |
{ | |
_ = InvokeAsync(async () => await JS.InvokeVoidAsync("console.time", e.RequestUri)); | |
} | |
} | |
private void HttpLoggerService_RequestStopped(object? sender, HttpResponseMessage e) | |
{ | |
if (JS != null && e.RequestMessage != null) | |
{ | |
_ = InvokeAsync(async () => await JS.InvokeVoidAsync("console.timeEnd", e.RequestMessage.RequestUri)); | |
} | |
} | |
public void Dispose() | |
{ | |
HttpLoggerService.RequestStarted -= HttpLoggerService_RequestStarted; | |
HttpLoggerService.RequestStopped -= HttpLoggerService_RequestStopped; | |
} | |
} | |
internal static class HttpLoggerService | |
{ | |
static HttpRequestsObserver _observer; | |
static IDisposable? _listener; | |
public static event EventHandler<HttpRequestMessage>? RequestStarted; | |
public static event EventHandler<HttpResponseMessage>? RequestStopped; | |
private static void RaiseRequestStarted(Guid id, HttpRequestMessage message) | |
{ | |
RequestStarted?.Invoke(null, message); | |
} | |
private static void RaiseRequestStopped(Guid id, HttpResponseMessage message) | |
{ | |
RequestStopped?.Invoke(null, message); | |
} | |
static HttpLoggerService() | |
{ | |
_observer = new HttpRequestsObserver(); | |
_listener = DiagnosticListener.AllListeners.Subscribe(_observer); | |
} | |
private sealed class HttpRequestsObserver : IDisposable, IObserver<DiagnosticListener> | |
{ | |
private IDisposable? _subscription; | |
public void OnNext(DiagnosticListener value) | |
{ | |
if (value.Name == "HttpHandlerDiagnosticListener") | |
{ | |
_subscription = value.Subscribe(new HttpHandlerDiagnosticListener()); | |
} | |
} | |
public void OnCompleted() { } | |
public void OnError(Exception error) { } | |
public void Dispose() | |
{ | |
_subscription?.Dispose(); | |
} | |
private sealed class HttpHandlerDiagnosticListener : IObserver<KeyValuePair<string, object?>> | |
{ | |
private static readonly AsyncLocal<Guid> _currentMessage = new(); | |
private static readonly Func<object, HttpRequestMessage> RequestAccessor = CreateGetRequest(); | |
private static readonly Func<object, HttpResponseMessage> ResponseAccessor = CreateGetResponse(); | |
public void OnCompleted() { } | |
public void OnError(Exception error) { } | |
public void OnNext(KeyValuePair<string, object?> value) | |
{ | |
if (value.Key == "System.Net.Http.HttpRequestOut.Start") | |
{ | |
var request = RequestAccessor(value.Value!); | |
var id = Guid.NewGuid(); | |
_currentMessage.Value = id; | |
RaiseRequestStarted(id, request); | |
} | |
else if (value.Key == "System.Net.Http.HttpRequestOut.Stop") | |
{ | |
var response = ResponseAccessor(value.Value!); | |
RaiseRequestStopped(_currentMessage.Value, response); | |
} | |
} | |
private static Func<object, HttpRequestMessage> CreateGetRequest() | |
{ | |
var requestDataType = Type.GetType("System.Net.Http.DiagnosticsHandler+ActivityStartData, System.Net.Http", throwOnError: true)!; | |
var requestProperty = requestDataType.GetProperty("Request")!; | |
return (object o) => (HttpRequestMessage)requestProperty.GetValue(o)!; | |
} | |
private static Func<object, HttpResponseMessage> CreateGetResponse() | |
{ | |
var requestDataType = Type.GetType("System.Net.Http.DiagnosticsHandler+ActivityStopData, System.Net.Http", throwOnError: true)!; | |
var requestProperty = requestDataType.GetProperty("Response")!; | |
return (object o) => (HttpResponseMessage)requestProperty.GetValue(o)!; | |
} | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@page "/" | |
<PageTitle>Index</PageTitle> | |
<h1>Hello, world!</h1> | |
Welcome to your new app. | |
<SurveyPrompt Title="How is Blazor working for you?" /> | |
@code { | |
static HttpClient httpClient = new(); | |
protected override async Task OnAfterRenderAsync(bool firstRender) | |
{ | |
await httpClient.GetStringAsync("http://example.com"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment