From 8c0b6614a12fb92b84efd326bab737bf2cf03bfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20St=C3=BChmer?= Date: Wed, 10 Dec 2025 22:36:29 +0100 Subject: [PATCH 1/4] feat: Added `Logging` --- Directory.Packages.props | 2 + ForgingBlazor.slnx | 1 + .../ApplicationBuilderExtensions.cs | 115 ++++++++++++++++++ .../NetEvolve.ForgingBlazor.Logging.csproj | 17 +++ .../ForgingBlazorApplicationBuilder.cs | 9 ++ .../Program.cs | 9 +- 6 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 src/NetEvolve.ForgingBlazor.Logging/ApplicationBuilderExtensions.cs create mode 100644 src/NetEvolve.ForgingBlazor.Logging/NetEvolve.ForgingBlazor.Logging.csproj diff --git a/Directory.Packages.props b/Directory.Packages.props index 5eff7b7..c340dc0 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -19,6 +19,8 @@ + + diff --git a/ForgingBlazor.slnx b/ForgingBlazor.slnx index aea312f..f7ac4e2 100644 --- a/ForgingBlazor.slnx +++ b/ForgingBlazor.slnx @@ -23,6 +23,7 @@ + diff --git a/src/NetEvolve.ForgingBlazor.Logging/ApplicationBuilderExtensions.cs b/src/NetEvolve.ForgingBlazor.Logging/ApplicationBuilderExtensions.cs new file mode 100644 index 0000000..73c9ef3 --- /dev/null +++ b/src/NetEvolve.ForgingBlazor.Logging/ApplicationBuilderExtensions.cs @@ -0,0 +1,115 @@ +namespace NetEvolve.ForgingBlazor.Logging; + +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using NetEvolve.ForgingBlazor.Extensibility.Abstractions; + +/// +/// Provides extension methods for to configure and integrate logging services +/// into the Forging Blazor application pipeline. +/// +/// +/// This class offers a fluent API for adding logging capabilities to applications built with the Forging Blazor framework. +/// It provides both pre-configured default logging setups and flexible custom configurations to meet various logging requirements. +/// +public static class ApplicationBuilderExtensions +{ + /// + /// Configures the application with default logging providers, including console and debug output. + /// + /// + /// The instance that represents the application being configured. + /// This parameter serves as the entry point for adding logging services to the application's service collection. + /// + /// + /// The same instance that was passed in, enabling method chaining + /// and fluent configuration of additional application features. + /// + /// + /// Thrown when is . + /// + /// + /// + /// This method provides a convenient way to quickly set up logging with sensible defaults. + /// It automatically configures both console and debug logging providers, which are suitable + /// for most development and debugging scenarios. + /// + /// + /// The console provider outputs log messages to the standard console output, while the debug provider + /// writes to the debug output window in development environments and attached debuggers. + /// + /// + /// For production scenarios or when specific logging providers are required, consider using the + /// overload that accepts an delegate for custom configuration. + /// + /// + /// + /// + /// var builder = ApplicationBuilder.Create(); + /// builder.WithLogging(); + /// + /// + /// + public static IApplicationBuilder WithLogging(this IApplicationBuilder builder) => + builder.WithLogging(configure => configure.AddConsole().AddDebug()); + + /// + /// Configures the application with custom logging providers using a flexible configuration delegate. + /// + /// + /// The instance that represents the application being configured. + /// This parameter serves as the entry point for adding logging services to the application's service collection. + /// + /// + /// An delegate that provides fine-grained control over the logging configuration. + /// This delegate receives an instance that can be used to add logging providers, + /// set minimum log levels, add filters, and perform other logging-related configurations. + /// + /// + /// The same instance that was passed in, enabling method chaining + /// and fluent configuration of additional application features. + /// + /// + /// Thrown when is . + /// + /// + /// + /// This method offers maximum flexibility for configuring logging in the Forging Blazor application. + /// It allows developers to choose specific logging providers, configure log levels, add custom filters, + /// and integrate third-party logging frameworks according to their application's requirements. + /// + /// + /// The configuration delegate is executed immediately during the application builder's configuration phase, + /// ensuring that logging services are properly registered before any application components attempt to use them. + /// + /// + /// Common use cases include integrating structured logging providers (such as Serilog or NLog), + /// configuring cloud-based logging services (like Application Insights or AWS CloudWatch), + /// or setting up custom logging filters for performance optimization. + /// + /// + /// + /// Example with custom log levels and multiple providers: + /// + /// var builder = ApplicationBuilder.Create(); + /// builder.WithLogging(logging => + /// { + /// logging.SetMinimumLevel(LogLevel.Information); + /// logging.AddConsole(); + /// logging.AddEventLog(); + /// logging.AddFilter("Microsoft", LogLevel.Warning); + /// }); + /// + /// + /// + /// + /// + public static IApplicationBuilder WithLogging(this IApplicationBuilder builder, Action configure) + { + ArgumentNullException.ThrowIfNull(builder); + + _ = builder.Services.AddLogging(configure); + + return builder; + } +} diff --git a/src/NetEvolve.ForgingBlazor.Logging/NetEvolve.ForgingBlazor.Logging.csproj b/src/NetEvolve.ForgingBlazor.Logging/NetEvolve.ForgingBlazor.Logging.csproj new file mode 100644 index 0000000..15b8a12 --- /dev/null +++ b/src/NetEvolve.ForgingBlazor.Logging/NetEvolve.ForgingBlazor.Logging.csproj @@ -0,0 +1,17 @@ + + + $(_ProjectTargetFrameworks) + $(PackageTags);logging + + + + + + + + + + + + + diff --git a/src/NetEvolve.ForgingBlazor/ForgingBlazorApplicationBuilder.cs b/src/NetEvolve.ForgingBlazor/ForgingBlazorApplicationBuilder.cs index 269ce0e..84f6e9c 100644 --- a/src/NetEvolve.ForgingBlazor/ForgingBlazorApplicationBuilder.cs +++ b/src/NetEvolve.ForgingBlazor/ForgingBlazorApplicationBuilder.cs @@ -98,6 +98,15 @@ public ForgingBlazorApplicationBuilder(string[] args) /// public IApplication Build() { + // Check if logging is already registered + if (!Services.IsServiceTypeRegistered()) + { + // Register NullLoggerFactory and NullLogger as defaults + _ = Services + .AddSingleton(NullLoggerFactory.Instance) + .AddSingleton(typeof(ILogger<>), typeof(NullLogger<>)); + } + var serviceProvider = Services.BuildServiceProvider(); return new ForgingBlazorApplication(_args, serviceProvider); diff --git a/tests/NetEvolve.ForgingBlazor.Tests.Console/Program.cs b/tests/NetEvolve.ForgingBlazor.Tests.Console/Program.cs index 15299b7..b482879 100644 --- a/tests/NetEvolve.ForgingBlazor.Tests.Console/Program.cs +++ b/tests/NetEvolve.ForgingBlazor.Tests.Console/Program.cs @@ -1,6 +1,13 @@ using NetEvolve.ForgingBlazor; -var builder = ForgingBlazorApplicationBuilder.CreateDefaultBuilder(args); +var arguments = args; + +if (arguments.Length == 0) +{ + arguments = ["build"]; +} + +var builder = ForgingBlazorApplicationBuilder.CreateDefaultBuilder(arguments); var app = builder.Build(); From d2ba7ac4c772e1ca8d841f42e2a5a7870fa3d8dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20St=C3=BChmer?= Date: Wed, 10 Dec 2025 22:37:23 +0100 Subject: [PATCH 2/4] fix: Added missing namespaces --- src/NetEvolve.ForgingBlazor/ForgingBlazorApplicationBuilder.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/NetEvolve.ForgingBlazor/ForgingBlazorApplicationBuilder.cs b/src/NetEvolve.ForgingBlazor/ForgingBlazorApplicationBuilder.cs index 84f6e9c..620223a 100644 --- a/src/NetEvolve.ForgingBlazor/ForgingBlazorApplicationBuilder.cs +++ b/src/NetEvolve.ForgingBlazor/ForgingBlazorApplicationBuilder.cs @@ -1,6 +1,8 @@ namespace NetEvolve.ForgingBlazor; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using NetEvolve.ForgingBlazor.Extensibility.Abstractions; /// From da4ba35b988fb7016dd8bea078daca769777d215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20St=C3=BChmer?= Date: Wed, 10 Dec 2025 22:41:35 +0100 Subject: [PATCH 3/4] fix: Added missing method `IsServiceTypeRegistered` --- .../ServiceCollectionExtensions.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/NetEvolve.ForgingBlazor/ServiceCollectionExtensions.cs diff --git a/src/NetEvolve.ForgingBlazor/ServiceCollectionExtensions.cs b/src/NetEvolve.ForgingBlazor/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..dab2c71 --- /dev/null +++ b/src/NetEvolve.ForgingBlazor/ServiceCollectionExtensions.cs @@ -0,0 +1,16 @@ +namespace NetEvolve.ForgingBlazor; + +using System.CommandLine; +using System.Diagnostics.CodeAnalysis; +using Microsoft.Extensions.DependencyInjection; +using NetEvolve.ForgingBlazor.Commands; +using NetEvolve.ForgingBlazor.Core.Models; +using NetEvolve.ForgingBlazor.Extensibility.Abstractions; +using NetEvolve.ForgingBlazor.Extensibility.Models; +using NetEvolve.ForgingBlazor.Services; + +internal static class ServiceCollectionExtensions +{ + internal static bool IsServiceTypeRegistered(this IServiceCollection builder) + where T : class => builder.Any(x => x.ServiceType == typeof(T)); +} From dcdd1131afbf21aaf0c141dc67915591663260c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20St=C3=BChmer?= Date: Wed, 10 Dec 2025 22:45:56 +0100 Subject: [PATCH 4/4] fix: Removed unnecessary namespaces --- src/NetEvolve.ForgingBlazor/ServiceCollectionExtensions.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/NetEvolve.ForgingBlazor/ServiceCollectionExtensions.cs b/src/NetEvolve.ForgingBlazor/ServiceCollectionExtensions.cs index dab2c71..dd39f82 100644 --- a/src/NetEvolve.ForgingBlazor/ServiceCollectionExtensions.cs +++ b/src/NetEvolve.ForgingBlazor/ServiceCollectionExtensions.cs @@ -1,13 +1,9 @@ namespace NetEvolve.ForgingBlazor; using System.CommandLine; -using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.DependencyInjection; using NetEvolve.ForgingBlazor.Commands; -using NetEvolve.ForgingBlazor.Core.Models; using NetEvolve.ForgingBlazor.Extensibility.Abstractions; -using NetEvolve.ForgingBlazor.Extensibility.Models; -using NetEvolve.ForgingBlazor.Services; internal static class ServiceCollectionExtensions {