From f39be92e61939e1d4346440c0145ed5543a614b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20N=C3=A4geli?= Date: Tue, 3 Dec 2024 22:29:53 +0100 Subject: [PATCH] Fix layouts no longer being lazy --- Modules/Layouting/Provider/HandlerWrapper.cs | 10 ++++ Modules/Layouting/Provider/LayoutBuilder.cs | 51 ++++++++++--------- .../Modules/Layouting/LayoutTests.cs | 22 ++++++++ 3 files changed, 59 insertions(+), 24 deletions(-) create mode 100644 Modules/Layouting/Provider/HandlerWrapper.cs diff --git a/Modules/Layouting/Provider/HandlerWrapper.cs b/Modules/Layouting/Provider/HandlerWrapper.cs new file mode 100644 index 00000000..a3e27e26 --- /dev/null +++ b/Modules/Layouting/Provider/HandlerWrapper.cs @@ -0,0 +1,10 @@ +using GenHTTP.Api.Content; + +namespace GenHTTP.Modules.Layouting.Provider; + +internal sealed class HandlerWrapper(IHandler handler) : IHandlerBuilder +{ + + public IHandler Build() => handler; + +} diff --git a/Modules/Layouting/Provider/LayoutBuilder.cs b/Modules/Layouting/Provider/LayoutBuilder.cs index 956cb4d9..2869d56f 100644 --- a/Modules/Layouting/Provider/LayoutBuilder.cs +++ b/Modules/Layouting/Provider/LayoutBuilder.cs @@ -6,13 +6,13 @@ public sealed class LayoutBuilder : IHandlerBuilder { private readonly List _Concerns = []; - private IHandler? _Index; + private IHandlerBuilder? _Index; #region Get-/Setters - private Dictionary RoutedHandlers { get; } + private Dictionary RoutedHandlers { get; } - private List RootHandlers { get; } + private List RootHandlers { get; } #endregion @@ -33,18 +33,26 @@ public LayoutBuilder() /// the index of the layout. /// /// The handler used for the index of the layout - public LayoutBuilder Index(IHandler handler) + public LayoutBuilder Index(IHandler handler) => Index(new HandlerWrapper(handler)); + + /// + /// Sets the handler which should be invoked to provide + /// the index of the layout. + /// + /// The handler used for the index of the layout + public LayoutBuilder Index(IHandlerBuilder handler) { _Index = handler; return this; } /// - /// Sets the handler which should be invoked to provide - /// the index of the layout. + /// Adds a handler that will be invoked for all URLs below + /// the specified path segment. /// - /// The handler used for the index of the layout - public LayoutBuilder Index(IHandlerBuilder handler) => Index(handler.Build()); + /// The name of the path segment to be handled + /// The handler which will handle the segment + public LayoutBuilder Add(string name, IHandler handler) => Add(new HandlerWrapper(handler)); /// /// Adds a handler that will be invoked for all URLs below @@ -52,7 +60,7 @@ public LayoutBuilder Index(IHandler handler) /// /// The name of the path segment to be handled /// The handler which will handle the segment - public LayoutBuilder Add(string name, IHandler handler) + public LayoutBuilder Add(string name, IHandlerBuilder handler) { if (name.Contains('/')) { @@ -63,14 +71,6 @@ public LayoutBuilder Add(string name, IHandler handler) return this; } - /// - /// Adds a handler that will be invoked for all URLs below - /// the specified path segment. - /// - /// The name of the path segment to be handled - /// The handler which will handle the segment - public LayoutBuilder Add(string name, IHandlerBuilder handler) => Add(name, handler.Build()); - /// /// Adds a handler on root level that will be invoked if neither a /// path segment has been detected nor the index has been invoked. @@ -81,11 +81,7 @@ public LayoutBuilder Add(string name, IHandler handler) /// Fallback handlers will be executed in the order they have been added /// to the layout. /// - public LayoutBuilder Add(IHandler handler) - { - RootHandlers.Add(handler); - return this; - } + public LayoutBuilder Add(IHandler handler) => Add(new HandlerWrapper(handler)); /// /// Adds a handler on root level that will be invoked if neither a @@ -97,7 +93,11 @@ public LayoutBuilder Add(IHandler handler) /// Fallback handlers will be executed in the order they have been added /// to the layout. /// - public LayoutBuilder Add(IHandlerBuilder handler) => Add(handler.Build()); + public LayoutBuilder Add(IHandlerBuilder handler) + { + RootHandlers.Add(handler); + return this; + } public LayoutBuilder Add(IConcernBuilder concern) { @@ -107,7 +107,10 @@ public LayoutBuilder Add(IConcernBuilder concern) public IHandler Build() { - return Concerns.Chain(_Concerns, new LayoutRouter(RoutedHandlers, RootHandlers, _Index)); + var routed = RoutedHandlers.ToDictionary(kv => kv.Key, kv => kv.Value.Build()); + var root = RootHandlers.Select(h => h.Build()).ToList(); + + return Concerns.Chain(_Concerns, new LayoutRouter(routed, root, _Index?.Build())); } #endregion diff --git a/Testing/Acceptance/Modules/Layouting/LayoutTests.cs b/Testing/Acceptance/Modules/Layouting/LayoutTests.cs index 68fa5321..bdb6009a 100644 --- a/Testing/Acceptance/Modules/Layouting/LayoutTests.cs +++ b/Testing/Acceptance/Modules/Layouting/LayoutTests.cs @@ -1,4 +1,5 @@ using System.Net; +using GenHTTP.Modules.Authentication; using GenHTTP.Modules.IO; using GenHTTP.Modules.Layouting; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -84,4 +85,25 @@ public void TestIllegalPathCharacters() { Layout.Create().Add("some/path", Content.From(Resource.FromString("Hello World"))); } + + [TestMethod] + [MultiEngineTest] + public async Task TestLazyBuilding(TestEngine engine) + { + var inner = Layout.Create(); + + var outer = Layout.Create() + .Add("inner", inner); + + // add a concern _after_ the inner handler has already been added + // still has to take effect + inner.Authentication((_, _) => new()); + + await using var host = await TestHost.RunAsync(outer, engine: engine); + + using var response = await host.GetResponseAsync("/inner/"); + + await response.AssertStatusAsync(HttpStatusCode.Unauthorized); + } + }