< Summary

Information
Class: NanoRoute.RouterBuilder
Assembly: NanoRoute.dll
File(s): /home/runner/work/nanoroute/nanoroute/Src/NanoRoute/Public/RouterBuilder.cs
Line coverage
100%
Covered lines: 21
Uncovered lines: 0
Coverable lines: 21
Total lines: 154
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/nanoroute/nanoroute/Src/NanoRoute/Public/RouterBuilder.cs

#LineLine coverage
 1/********************************************************************************
 2* RouterBuilder.cs                                                              *
 3*                                                                               *
 4* Author: Denes Solti                                                           *
 5********************************************************************************/
 6using System;
 7
 8namespace NanoRoute
 9{
 10    using Internals;
 11
 12    /// <summary>
 13    /// Builds a concrete <see cref="Router"/> type together with its strongly typed configuration object.
 14    /// </summary>
 15    /// <typeparam name="TRouter">The router type produced by <see cref="CreateRouter"/>.</typeparam>
 16    /// <typeparam name="TConfig">The configuration type exposed by <see cref="RouterConfig"/>.</typeparam>
 17    /// <example>
 18    /// <code>
 19    /// MyRouter router = MyRouter
 20    ///     .CreateBuilder()
 21    ///     .AddDefaultValueParsers()
 22    ///     .AddHandler("GET", "/health/", (context, _) =&gt; Results.Ok())
 23    ///     .CreateRouter();
 24    /// </code>
 25    /// </example>
 26    public sealed class RouterBuilder<TRouter, TConfig> : RouteScopeBuilder where TRouter : Router where TConfig : Route
 27    {
 28        private readonly RouterFactoryDelegate<TRouter, TConfig> _routerFactory;
 29
 30        /// <summary>
 31        /// Creates a builder that can produce <typeparamref name="TRouter"/> instances.
 32        /// </summary>
 33        /// <param name="routerFactory">
 34        /// A factory that receives this builder and returns a router backed by its current route snapshot.
 35        /// </param>
 36        /// <exception cref="ArgumentNullException">Thrown when <paramref name="routerFactory"/> is <see langword="null"
 237        public RouterBuilder(RouterFactoryDelegate<TRouter, TConfig> routerFactory) : base()
 238        {
 239            Ensure.NotNull(routerFactory);
 40
 241            _routerFactory = routerFactory;
 242        }
 43
 44        /// <summary>
 45        /// Registers a parser that can convert a route segment into a typed value and bind parser arguments once during
 46        /// </summary>
 47        /// <param name="parserName">The name used in route patterns such as <c>{id:int(min=1)}</c>.</param>
 48        /// <param name="bindArguments">Converts raw parser arguments into typed values once per route-template branch.<
 49        /// <param name="tryParseDelegate">The delegate that validates and parses a single path segment.</param>
 50        /// <returns>The current <see cref="RouterBuilder{TRouter, TConfig}"/> instance.</returns>
 51        /// <exception cref="ArgumentNullException">
 52        /// Thrown when <paramref name="parserName"/>, <paramref name="bindArguments"/>, or
 53        /// <paramref name="tryParseDelegate"/> is <see langword="null"/>.
 54        /// </exception>
 55        /// <example>
 56        /// <code>
 57        /// builder.AddValueParser("slug", static rawArgs =&gt; null, static context =&gt;
 58        ///     ValueTask.FromResult(new ValueParseResult(context.Segment.Length &gt; 0, context.Segment.ToString())));
 59        /// </code>
 60        /// </example>
 61        public new RouterBuilder<TRouter, TConfig> AddValueParser(string parserName, BindArgumentsDelegate bindArguments
 162        {
 163            base.AddValueParser(parserName, bindArguments, tryParseDelegate);
 164            return this;
 165        }
 66
 67        /// <summary>
 68        /// Registers a handler for a single HTTP method.
 69        /// </summary>
 70        /// <param name="verb">The HTTP method that activates the handler.</param>
 71        /// <param name="pattern">
 72        /// The route pattern to match. Literal segments are matched case-insensitively, parameter segments use
 73        /// registered parsers in the form <c>{parameterName:parserName}</c>. Exact patterns must end with
 74        /// <c>/</c>, and prefix patterns must end with <c>/*</c>.
 75        /// </param>
 76        /// <param name="handler">
 77        /// The handler to execute. If several handlers match, calling the supplied <c>next</c> delegate continues
 78        /// the pipeline with the next compatible handler from the already selected route branch.
 79        /// </param>
 80        /// <returns>The current router instance.</returns>
 81        /// <exception cref="ArgumentNullException">
 82        /// Thrown when <paramref name="verb"/>, <paramref name="pattern"/>, or <paramref name="handler"/> is
 83        /// <see langword="null"/>.
 84        /// </exception>
 85        /// <exception cref="ArgumentException">Thrown when <paramref name="verb"/> is not a supported HTTP method.</exc
 86        /// <exception cref="ArgumentException">Thrown when <paramref name="pattern"/> has invalid route-template syntax
 87        /// <exception cref="InvalidOperationException">
 88        /// Thrown when <paramref name="pattern"/> uses an unsupported optional parameter or list parser, references
 89        /// a value parser that has not been registered yet, or reuses a parser-backed branch with a different
 90        /// parameter name.
 91        /// </exception>
 92        /// <example>
 93        /// <code>
 94        /// builder.AddHandler("GET", "/files/{path:any}/*", (context, next) =&gt;
 95        /// {
 96        ///     string path = (string) context.Parameters["path"]!;
 97        ///     return ServeFile(path);
 98        /// });
 99        /// </code>
 100        /// </example>
 101        public new RouterBuilder<TRouter, TConfig> AddHandler(string verb, string pattern, RequestHandlerDelegate handle
 2102        {
 2103            base.AddHandler(verb, pattern, handler);
 2104            return this;
 2105        }
 106
 107        /// <summary>
 108        /// Updates the router configuration object that will be used by future router instances.
 109        /// </summary>
 110        /// <param name="updateConfig">A callback that returns the updated <see cref="RouterConfig"/> instance.</param>
 111        /// <returns>The current builder.</returns>
 112        /// <exception cref="ArgumentNullException">
 113        /// Thrown when <paramref name="updateConfig"/> is <see langword="null"/> or returns <see langword="null"/>.
 114        /// </exception>
 115        /// <example>
 116        /// <code>
 117        /// builder.ConfigureRouting(config =&gt; config with
 118        /// {
 119        ///     MatchingPrecedence = MatchingPrecedence.ParameterizedFirst
 120        /// });
 121        /// </code>
 122        /// </example>
 123        public RouterBuilder<TRouter, TConfig> ConfigureRouting(ConfigureBuilderDelegate<TConfig> updateConfig)
 2124        {
 2125            Ensure.NotNull(updateConfig);
 126
 2127            RouterConfig = updateConfig(RouterConfig);
 2128            Ensure.NotNull(RouterConfig);
 129
 2130            return this;
 2131        }
 132
 133        /// <summary>
 134        /// Gets the configuration object applied when <see cref="CreateRouter"/> is called.
 135        /// </summary>
 2136        public TConfig RouterConfig { get; private set; } = new();
 137
 138        /// <summary>
 139        /// Creates a router from the builder's current routes, parser registrations, and configuration.
 140        /// </summary>
 141        /// <returns>A new <typeparamref name="TRouter"/> instance.</returns>
 142        /// <remarks>
 143        /// The created router is an immutable snapshot. Later changes to the builder or its configuration do not
 144        /// affect routers that have already been created.
 145        /// </remarks>
 146        /// <example>
 147        /// <code>
 148        /// MyRouter router = builder.CreateRouter();
 149        /// </code>
 150        /// </example>
 2151        public TRouter CreateRouter() => _routerFactory(this);
 152    }
 153}
 154