Skip to content

Commit abb3fc9

Browse files
committed
fix: HostBuilder.Build() shares LogExtensionPoint.AmbientLoggerFactory
Fixes: #3008 Context: unoplatform/uno.templates#1921 `dotnet new unoapp` templates have two patterns for `ILogger` configuration: 1. The *recommended* pattern, which uses Dependency Injection (DI) via [`.UseLogging()`][0]: dotnet new unoapp -preset "recommended" 2. The "No Dependency Injection" (NoDI) pattern, which *doesn't* use Dependency Injection, and instead has an [`App.InitializeLogging()`][1] method called from [`Main()`][2]: dotnet new unoapp -di False The wonderful thing is, those log *different*, non-overlapping, things. The Dependency Injection pattern provides an `ILogger` instance to constructors of types registered with e.g. [`services.AddSingleton()`][3]: services.AddSingleton<IMyService, MyService>() // … interface IMyService; class MyService : IMyService { public MyService(ILogger<MyService> logger) => …; } The "No Dependency Injection" pattern provides `ILogger` instances from the [`Log<T>(T)` extension method][4], which is used extensively within Uno itself, e.g. // https://github.com/unoplatform/uno/blob/77c6ca0533a63be48c6bbdd830c8653e17a9b0fa/src/Uno.UI.Dispatching/Native/NativeDispatcher.cs#L146 dispatcher.Log().Error("NativeDispatcher unhandled exception", exception); Using only DI logging initialization will miss NoDI messages. Using only NoDI logging initialization will miss DI messages. In order to capture *all* `ILogger`-originated messages, *both* DI and NoDI log initialization patterns must be used, which is *not* done by *any* `dotnet new unoapp` templates. Additionally, DI-based logging is *optional* -- it can be disabled via `dotnet new unoapp -di False …` -- and thus its presence cannot necessarily be relied upon. Attempt to begin improving this scenario by updating `HostBuilder.CreateServiceProvider()` (via `HostBuilder.Build()`) to [Replace][5] the `ILoggerFactory` registration added by `.AddLogging()` with the `ILoggerFactory` instance stored by `Uno.Extensions.LogExtensionPoint.AmbientLoggerFactory`. This means that *if* NoDI init is performed *before* `HostBuilder.Build()` is invoked, then the `ILoggerFactory` instance created as part of NoDI init is also registered with `IHost.Services`. This in turn means that if NoDI init is performed *and not* DI init, registered services will obtain an `ILogger` instance which follows the NoDI init configuration. Meaning that *only* NoDI init will be required to see *both* NoDI *and* DI-originating messages. [0]: https://github.com/unoplatform/uno.templates/blob/8988cac5efc444de0afeb400da1da24620b5c083/src/Uno.Templates/content/unoapp/MyExtensionsApp.1/App.recommended.cs#L81-L112 [1]: https://github.com/unoplatform/uno.templates/blob/8988cac5efc444de0afeb400da1da24620b5c083/src/Uno.Templates/content/unoapp/MyExtensionsApp.1/App.blank.cs#L115-L182 [2]: https://github.com/unoplatform/uno.templates/blob/8988cac5efc444de0afeb400da1da24620b5c083/src/Uno.Templates/content/unoapp/MyExtensionsApp.1/Platforms/Desktop/Program.cs#L10-L14 [3]: https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.servicecollectionserviceextensions.addsingleton?view=net-10.0-pp [4]: https://platform.uno/docs/articles/logging.html#uno-logging-extensions [5]: https://learn.microsoft.com/dotnet/api/microsoft.extensions.dependencyinjection.extensions.servicecollectiondescriptorextensions.replace?view=net-10.0-pp#microsoft-extensions-dependencyinjection-extensions-servicecollectiondescriptorextensions-replace(microsoft-extensions-dependencyinjection-iservicecollection-microsoft-extensions-dependencyinjection-servicedescriptor)
1 parent 5235975 commit abb3fc9

File tree

2 files changed

+9
-0
lines changed

2 files changed

+9
-0
lines changed

src/Uno.Extensions.Hosting.UI/HostBuilder.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Marking as auto-generated to prevent StyleCop including this file - Taken from Microsoft.Extensions.Hosting
22
// <auto-generated />
33

4+
using Microsoft.Extensions.DependencyInjection.Extensions;
5+
46
namespace Uno.Extensions.Hosting;
57

68
/// <inheritdoc cref="IHostBuilder" />
@@ -241,6 +243,12 @@ private void CreateServiceProvider()
241243
//services.AddOptions().Configure<HostOptions>(options => { options.Initialize(_hostConfiguration); });
242244
services.AddLogging();
243245

246+
var ambientFactory = Uno.Extensions.LogExtensionPoint.AmbientLoggerFactory;
247+
if (ambientFactory is not null)
248+
{
249+
services.Replace(ServiceDescriptor.Singleton(typeof(ILoggerFactory), ambientFactory));
250+
}
251+
244252
foreach (Action<HostBuilderContext, IServiceCollection> configureServicesAction in _configureServicesActions)
245253
{
246254
configureServicesAction(_hostBuilderContext!, services);

src/Uno.Extensions.Hosting.UI/Uno.Extensions.Hosting.WinUI.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
<ItemGroup>
2020
<PackageReference Include="Microsoft.Extensions.Hosting" />
21+
<PackageReference Include="Uno.Core.Extensions.Logging.Singleton" />
2122
</ItemGroup>
2223

2324
<ItemGroup Condition="'$(IsBrowserWasm)'!='true'">

0 commit comments

Comments
 (0)