From 685d65cff1c91d302096353f85805a91c6fe7950 Mon Sep 17 00:00:00 2001 From: Vincent van Proosdij <164303+vip32@users.noreply.github.com> Date: Fri, 11 Oct 2024 00:32:01 +0200 Subject: [PATCH] Better module matching for inbound http resuests (modulecontextaccessors) --- .../Accessors/RequestModuleContextAccessor.cs | 49 ++++++++++++++++--- .../TypeNameModuleContextAccessor.cs | 27 ++++++++++ 2 files changed, 70 insertions(+), 6 deletions(-) diff --git a/src/Common.Modules/Accessors/RequestModuleContextAccessor.cs b/src/Common.Modules/Accessors/RequestModuleContextAccessor.cs index 32b125bd..c97f623f 100644 --- a/src/Common.Modules/Accessors/RequestModuleContextAccessor.cs +++ b/src/Common.Modules/Accessors/RequestModuleContextAccessor.cs @@ -7,11 +7,27 @@ namespace BridgingIT.DevKit.Common; using Microsoft.AspNetCore.Http; +/// +/// Manages the context for request modules by providing functionality to +/// find the appropriate module based on the provided HTTP request. +/// public class RequestModuleContextAccessor : IRequestModuleContextAccessor { + /// + /// A variable representing a collection of modules within the application framework. + /// Utilized within RequestModuleContextAccessor for providing functionalities such as finding + /// the appropriate module based on a provided HTTP request. + /// private readonly IEnumerable modules; + + /// + /// An array of string paths used to identify specific modules within HTTP requests. + /// private readonly string[] pathSelectors = ["/api/v", "/api"]; + /// + /// Provides functionality for accessing the appropriate module based on the provided HTTP request. + /// public RequestModuleContextAccessor(IEnumerable modules = null, string[] pathSelectors = null) { this.modules = modules.SafeNull(); @@ -22,6 +38,11 @@ public RequestModuleContextAccessor(IEnumerable modules = null, string[ } } + /// + /// Finds the appropriate module based on the provided HTTP request. + /// + /// The HTTP request used to determine the module. + /// The module associated with the HTTP request, or null if no module is found. public virtual IModule Find(HttpRequest request) { request.Headers.TryGetValue(ModuleConstants.ModuleNameKey, out var moduleName); @@ -31,14 +52,30 @@ public virtual IModule Find(HttpRequest request) moduleName = request.Query[ModuleConstants.ModuleNameKey]; } - foreach (var pathSelector in this.pathSelectors.SafeNull()) + if (string.IsNullOrWhiteSpace(moduleName)) + { + foreach (var module in this.modules) // check if modulename is part of path + { + if (request.Path.Value != null && + request.Path.Value.Contains($"/{module.Name}/", StringComparison.OrdinalIgnoreCase)) + { + moduleName = module.Name; + break; + } + } + } + + if (string.IsNullOrWhiteSpace(moduleName)) { - if (string.IsNullOrWhiteSpace(moduleName) && - request.Path.Value.Contains(pathSelector, StringComparison.OrdinalIgnoreCase)) + foreach (var pathSelector in this.pathSelectors.SafeNull()) // check if module is found with the path selectors { - // TODO: source generated regex? api/MODULENAME/controller - moduleName = request.Path.Value.SliceFrom(pathSelector); - moduleName = moduleName.ToString().SliceFrom("/").SliceTill("/"); + if (string.IsNullOrWhiteSpace(moduleName) && + request.Path.Value.Contains(pathSelector, StringComparison.OrdinalIgnoreCase)) + { + // TODO: source generated regex? api/MODULENAME/controller + moduleName = request.Path.Value.SliceFrom(pathSelector); + moduleName = moduleName.ToString().SliceFrom("/").SliceTill("/"); + } } } diff --git a/src/Common.Modules/Accessors/TypeNameModuleContextAccessor.cs b/src/Common.Modules/Accessors/TypeNameModuleContextAccessor.cs index 1434736e..dec4a850 100644 --- a/src/Common.Modules/Accessors/TypeNameModuleContextAccessor.cs +++ b/src/Common.Modules/Accessors/TypeNameModuleContextAccessor.cs @@ -5,12 +5,34 @@ namespace BridgingIT.DevKit.Common; +/// +/// TypeNameModuleContextAccessor provides a mechanism to access module contexts based on the type names. +/// +/// +/// This class implements the interface and allows retrieving modules by their type name. +/// A customizable delegate function can be used to select the module name from a given type. +/// public class TypeNameModuleContextAccessor : IModuleContextAccessor { + /// + /// A delegate function used to select the module name from a specified type. + /// + /// + /// This function is typically used within the class to extract + /// a module name from its representation. + /// By default, this function extracts the module name by slicing the type's full name between "Modules." + /// and the next "." character. + /// private readonly Func moduleNameSelector = t => t.FullName.SliceFrom("Modules.").SliceTill("."); + /// + /// Represents an accessor for module context which allows finding modules by their types. + /// private readonly IEnumerable modules; + /// + /// Provides a mechanism to access module context information by type name. + /// public TypeNameModuleContextAccessor( IEnumerable modules = null, Func moduleNameSelector = null) @@ -23,6 +45,11 @@ public TypeNameModuleContextAccessor( } } + /// + /// Finds an IModule instance that corresponds to the provided type based on the module name selector. + /// + /// The type for which the corresponding module needs to be found. + /// An IModule instance if a matching module is found; otherwise, null. public virtual IModule Find(Type type) { return this.modules.FirstOrDefault(m => m.Name.SafeEquals(this.moduleNameSelector(type)));