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 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 webserver at {_baseUrl} ..."); HttpListener server = new HttpListener(); server.Prefixes.Add(_baseUrl); server.Start(); _logger.LogInfo("server started"); long requestId = 1; while (!_stopToken.IsCancellationRequested) { var ctx = await server.GetContextAsync().AsCancellable(_stopToken); HandleRequestAsync(ctx, requestId); requestId++; } // stop 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 status = await _router.Resolve(ctx); _logger.LogInfo(logContext, $"{(int)status} ({status})"); } catch (Exception ex) { _logger.LogWarn(logContext, ex); } } }