DTLib/DTLib.Web/WebApp.cs

73 lines
2.2 KiB
C#

global using System;
global using System.Collections.Generic;
global using System.Text;
global using System.Threading;
global using System.Threading.Tasks;
global using DTLib.Filesystem;
global using DTLib.Logging;
global using System.Net;
using System.Diagnostics;
using DTLib.Extensions;
using DTLib.Web.Routes;
namespace DTLib.Web;
public class WebApp
{
private readonly string _baseUrl;
private readonly ContextLogger _logger;
private readonly IRouter _router;
private readonly CancellationToken _stopToken;
public WebApp(string baseUrl, ILogger logger, IRouter router, CancellationToken stopToken = default)
{
_logger = new ContextLogger(nameof(WebApp), logger);
_baseUrl = baseUrl;
_stopToken = stopToken;
_router = router;
}
public async Task Run()
{
_logger.LogInfo($"starting server at '{_baseUrl}'...");
HttpListener server = new HttpListener();
server.Prefixes.Add(_baseUrl);
server.Start();
_logger.LogInfo("server started");
long requestId = 1;
try
{
while (!_stopToken.IsCancellationRequested)
{
var ctx = await server.GetContextAsync().AsCancellable(_stopToken);
HandleRequestAsync(ctx, requestId++);
}
}
catch (OperationCanceledException)
{}
server.Stop();
_logger.LogInfo("server stopped");
}
// ReSharper disable once AsyncVoidMethod
private async void HandleRequestAsync(HttpListenerContext ctx, long requestId)
{
string logContext = $"Request-{requestId}";
try
{
_logger.LogInfo(logContext, $"[{ctx.Request.HttpMethod}] {ctx.Request.RawUrl} from {ctx.Request.RemoteEndPoint}...");
var stopwatch = new Stopwatch();
stopwatch.Start();
var status = await _router.Resolve(ctx);
stopwatch.Stop();
_logger.LogInfo(logContext, $"responded {(int)status} ({status}) in {stopwatch.ElapsedMilliseconds}ms");
}
catch (Exception ex)
{
_logger.LogWarn(logContext, ex);
}
}
}