Skip to content

Commit

Permalink
Better module matching for inbound http resuests (modulecontextaccess…
Browse files Browse the repository at this point in the history
…ors)
  • Loading branch information
vip32 committed Oct 10, 2024
1 parent 530092e commit 685d65c
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 6 deletions.
49 changes: 43 additions & 6 deletions src/Common.Modules/Accessors/RequestModuleContextAccessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,27 @@ namespace BridgingIT.DevKit.Common;

using Microsoft.AspNetCore.Http;

/// <summary>
/// Manages the context for request modules by providing functionality to
/// find the appropriate module based on the provided HTTP request.
/// </summary>
public class RequestModuleContextAccessor : IRequestModuleContextAccessor
{
/// <summary>
/// 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.
/// </summary>
private readonly IEnumerable<IModule> modules;

/// <summary>
/// An array of string paths used to identify specific modules within HTTP requests.
/// </summary>
private readonly string[] pathSelectors = ["/api/v", "/api"];

/// <summary>
/// Provides functionality for accessing the appropriate module based on the provided HTTP request.
/// </summary>
public RequestModuleContextAccessor(IEnumerable<IModule> modules = null, string[] pathSelectors = null)
{
this.modules = modules.SafeNull();
Expand All @@ -22,6 +38,11 @@ public RequestModuleContextAccessor(IEnumerable<IModule> modules = null, string[
}
}

/// <summary>
/// Finds the appropriate module based on the provided HTTP request.
/// </summary>
/// <param name="request">The HTTP request used to determine the module.</param>
/// <returns>The module associated with the HTTP request, or null if no module is found.</returns>
public virtual IModule Find(HttpRequest request)
{
request.Headers.TryGetValue(ModuleConstants.ModuleNameKey, out var moduleName);
Expand All @@ -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("/");
}
}
}

Expand Down
27 changes: 27 additions & 0 deletions src/Common.Modules/Accessors/TypeNameModuleContextAccessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,34 @@

namespace BridgingIT.DevKit.Common;

/// <summary>
/// TypeNameModuleContextAccessor provides a mechanism to access module contexts based on the type names.
/// </summary>
/// <remarks>
/// This class implements the <see cref="IModuleContextAccessor"/> 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.
/// </remarks>
public class TypeNameModuleContextAccessor : IModuleContextAccessor
{
/// <summary>
/// A delegate function used to select the module name from a specified type.
/// </summary>
/// <remarks>
/// This function is typically used within the <see cref="TypeNameModuleContextAccessor"/> class to extract
/// a module name from its <see cref="Type"/> representation.
/// By default, this function extracts the module name by slicing the type's full name between "Modules."
/// and the next "." character.
/// </remarks>
private readonly Func<Type, string> moduleNameSelector = t => t.FullName.SliceFrom("Modules.").SliceTill(".");

/// <summary>
/// Represents an accessor for module context which allows finding modules by their types.
/// </summary>
private readonly IEnumerable<IModule> modules;

/// <summary>
/// Provides a mechanism to access module context information by type name.
/// </summary>
public TypeNameModuleContextAccessor(
IEnumerable<IModule> modules = null,
Func<Type, string> moduleNameSelector = null)
Expand All @@ -23,6 +45,11 @@ public TypeNameModuleContextAccessor(
}
}

/// <summary>
/// Finds an IModule instance that corresponds to the provided type based on the module name selector.
/// </summary>
/// <param name="type">The type for which the corresponding module needs to be found.</param>
/// <returns>An IModule instance if a matching module is found; otherwise, null.</returns>
public virtual IModule Find(Type type)
{
return this.modules.FirstOrDefault(m => m.Name.SafeEquals(this.moduleNameSelector(type)));
Expand Down

0 comments on commit 685d65c

Please sign in to comment.