From 726f14d1a1dbd206d8c20fd63ddb933bbf8b0b9f Mon Sep 17 00:00:00 2001 From: Eilon Lipton Date: Thu, 22 Jul 2021 13:28:12 -0700 Subject: [PATCH 1/7] WIP: Startup/host unification --- eng/Microsoft.Extensions.targets | 16 +- eng/Version.Details.xml | 4 + eng/Versions.props | 1 + .../BlazorWebViewRegistrationExtensions.cs | 5 +- .../ControlGallery/src/Core/Startup.cs | 15 +- .../ControlGallery/src/WinUI/App.xaml.cs | 2 +- .../ControlGallery/src/WinUI/WinUIStartup.cs | 11 +- .../ControlGallery/src/iOS/AppDelegate.cs | 5 +- .../src/AppHostBuilderExtensions.Android.cs | 2 +- .../src/AppHostBuilderExtensions.Standard.cs | 2 +- .../src/AppHostBuilderExtensions.Windows.cs | 2 +- .../Core/src/AppHostBuilderExtensions.cs | 58 ++-- .../Core/src/AppHostBuilderExtensions.iOS.cs | 2 +- .../Controls.Sample.Droid/MainApplication.cs | 6 +- .../AppDelegate.cs | 3 +- .../Platforms/Android/MainApplication.cs | 4 +- .../Platforms/MacCatalyst/AppDelegate.cs | 3 +- .../Platforms/iOS/AppDelegate.cs | 3 +- .../Controls.Sample.Profiling/Startup.cs | 8 +- .../MainWindow.cs | 2 +- .../Platforms/Android/MainApplication.cs | 4 +- .../Platforms/MacCatalyst/AppDelegate.cs | 3 +- .../Platforms/Windows/App.xaml.cs | 5 +- .../Platforms/iOS/AppDelegate.cs | 3 +- .../Controls.Sample.SingleProject/Startup.cs | 20 +- .../samples/Controls.Sample.WinUI/App.xaml.cs | 2 +- .../Controls.Sample.iOS/AppDelegate.cs | 3 +- .../BordelessEntryAppHostBuilderExtensions.cs | 12 +- .../BordelessEntryServiceBuilder.cs | 51 ++- .../Extensions/EssentialsExtensions.cs | 126 +++++--- .../samples/Controls.Sample/Startup.cs | 44 ++- .../src/Core/Controls.Core-net6.csproj | 9 + src/Controls/src/Core/Controls.Core.csproj | 8 + .../Effects/AppHostBuilderExtensions.cs | 86 ++--- .../Core.UnitTests/HostBuilderAppTests.cs | 19 +- .../Core.UnitTests/HostBuilderHandlerTests.cs | 20 +- src/Core/src/Core-net6.csproj | 2 + src/Core/src/Core.csproj | 4 +- src/Core/src/Core/BootstrapHostBuilder.cs | 172 ++++++++++ src/Core/src/Core/ConfigureHostBuilder.cs | 126 ++++++++ .../src/Core/FontsMauiAppBuilderExtensions.cs | 82 +++++ .../Core/HandlerMauiAppBuilderExtensions.cs | 36 +++ src/Core/src/Core/IStartup.cs | 29 -- .../ImageSourcesMauiAppBuilderExtensions.cs | 66 ++++ src/Core/src/Core/MauiApp.cs | 87 +++++ src/Core/src/Core/MauiAppBuilder.cs | 167 ++++++++++ .../Core/MauiApplicationServiceCollection.cs | 103 ++++++ .../Animations/AppHostBuilderExtensions.cs | 13 +- src/Core/src/Hosting/AppHost.cs | 21 -- src/Core/src/Hosting/AppHostBuilder.cs | 280 ----------------- .../src/Hosting/AppHostBuilderExtensions.cs | 90 ------ .../Hosting/Fonts/AppHostBuilderExtensions.cs | 53 ---- src/Core/src/Hosting/IAppHost.cs | 9 - src/Core/src/Hosting/IAppHostBuilder.cs | 21 -- .../src/Hosting/IMauiInitializeService.cs | 10 + src/Core/src/Hosting/IMauiServiceBuilder.cs | 13 - .../ImageSources/AppHostBuilderExtensions.cs | 47 --- .../IImageSourceServiceCollection.cs | 2 +- .../ImageSourceServiceProvider.cs | 2 +- src/Core/src/Hosting/Internal/AppHost.cs | 59 ---- .../Hosting/Internal/AppHostEnvironment.cs | 18 -- .../Internal/MauiHandlersServiceProvider.cs | 21 +- .../Hosting/Internal/MauiServiceProvider.cs | 2 + .../AppHostBuilderExtensions.Android.cs | 2 +- .../AppHostBuilderExtensions.Standard.cs | 2 +- .../AppHostBuilderExtensions.Windows.cs | 2 +- .../AppHostBuilderExtensions.cs | 32 +- .../AppHostBuilderExtensions.iOS.cs | 2 +- src/Core/src/Hosting/StartupExtensions.cs | 20 -- .../src/HotReload/AppHostBuilderExtensions.cs | 16 +- .../LifecycleEvents/LifecycleEventService.cs | 13 +- .../src/Platform/Android/MauiApplication.cs | 30 +- .../Platform/Windows/MauiWinUIApplication.cs | 27 +- .../Platform/iOS/MauiUIApplicationDelegate.cs | 26 +- .../Benchmarks/GetHandlersBenchmarker.cs | 10 +- .../MauiServiceProviderBenchmarker.cs | 117 ++++--- .../Benchmarks/RegisterHandlersBenchmarker.cs | 6 +- .../DeviceTests/Handlers/HandlerTestBase.cs | 21 +- .../DeviceTests/Platforms/Windows/App.xaml.cs | 5 +- .../FontImageSourceServiceTests.Android.cs | 8 +- .../FontImageSourceServiceTests.iOS.cs | 8 +- .../ImageSource/ImageSourceServiceTests.cs | 7 +- src/Core/tests/DeviceTests/Startup.cs | 9 +- .../UnitTests/AbstractViewHandlerTests.cs | 2 +- .../HostBuilderAppConfigurationTests.cs | 31 +- .../Hosting/HostBuilderFontsTests.cs | 43 +-- .../Hosting/HostBuilderHandlerTests.cs | 64 ++-- .../Hosting/HostBuilderImageSourceTests.cs | 31 +- .../Hosting/HostBuilderServiceBuilderTests.cs | 164 +--------- .../Hosting/HostBuilderServicesTests.cs | 297 +++++++----------- .../ImageSource/ImageSourceServiceTests.cs | 8 +- .../LifecycleEvents/LifecycleEventsTests.cs | 56 ++-- .../Platforms/Android/MainApplication.cs | 4 +- .../Platforms/MacCatalyst/AppDelegate.cs | 3 +- .../Samples/Platforms/Windows/App.xaml.cs | 3 +- .../Samples/Platforms/iOS/AppDelegate.cs | 3 +- src/Essentials/samples/Samples/Startup.cs | 11 +- .../DeviceTests/Platforms/Windows/App.xaml.cs | 5 +- src/Essentials/test/DeviceTests/Startup.cs | 9 +- .../Platforms/Windows/App.xaml.cs | 5 +- .../samples/DeviceTests.Sample/Startup.cs | 12 +- .../RunnerGenerator.cs | 17 +- .../AppHostBuilderExtensions.cs | 15 +- .../iOS/MauiTestApplicationDelegate.cs | 21 +- 104 files changed, 1685 insertions(+), 1586 deletions(-) create mode 100644 src/Core/src/Core/BootstrapHostBuilder.cs create mode 100644 src/Core/src/Core/ConfigureHostBuilder.cs create mode 100644 src/Core/src/Core/FontsMauiAppBuilderExtensions.cs create mode 100644 src/Core/src/Core/HandlerMauiAppBuilderExtensions.cs delete mode 100644 src/Core/src/Core/IStartup.cs create mode 100644 src/Core/src/Core/ImageSourcesMauiAppBuilderExtensions.cs create mode 100644 src/Core/src/Core/MauiApp.cs create mode 100644 src/Core/src/Core/MauiAppBuilder.cs create mode 100644 src/Core/src/Core/MauiApplicationServiceCollection.cs delete mode 100644 src/Core/src/Hosting/AppHost.cs delete mode 100644 src/Core/src/Hosting/AppHostBuilder.cs delete mode 100644 src/Core/src/Hosting/AppHostBuilderExtensions.cs delete mode 100644 src/Core/src/Hosting/Fonts/AppHostBuilderExtensions.cs delete mode 100644 src/Core/src/Hosting/IAppHost.cs delete mode 100644 src/Core/src/Hosting/IAppHostBuilder.cs create mode 100644 src/Core/src/Hosting/IMauiInitializeService.cs delete mode 100644 src/Core/src/Hosting/IMauiServiceBuilder.cs delete mode 100644 src/Core/src/Hosting/ImageSources/AppHostBuilderExtensions.cs delete mode 100644 src/Core/src/Hosting/Internal/AppHost.cs delete mode 100644 src/Core/src/Hosting/Internal/AppHostEnvironment.cs delete mode 100644 src/Core/src/Hosting/StartupExtensions.cs diff --git a/eng/Microsoft.Extensions.targets b/eng/Microsoft.Extensions.targets index 7510be16cb19..d15d1b07c10d 100644 --- a/eng/Microsoft.Extensions.targets +++ b/eng/Microsoft.Extensions.targets @@ -3,19 +3,7 @@ <_UseNet6Packages Condition=" '$(TargetFramework.Contains(net6.0))' == 'true' or '$(PackageType)' == 'DotnetPlatform' ">true - <_MicrosoftHostingVersion>5.0.0 4.7.0 - (_MicrosoftHostingVersion) - $(_MicrosoftHostingVersion) - $(_MicrosoftHostingVersion) - 5.0.1 - $(_MicrosoftHostingVersion) - $(_MicrosoftHostingVersion) - $(_MicrosoftHostingVersion) - $(_MicrosoftHostingVersion) - $(_MicrosoftHostingVersion) - $(_MicrosoftHostingVersion) - $(_MicrosoftHostingVersion) @@ -69,6 +57,10 @@ Update="Microsoft.Extensions.FileProviders.Abstractions" Version="$(MicrosoftExtensionsFileProvidersAbstractionsPackageVersion)" /> + https://github.com/dotnet/runtime 14b34eb02bc8969b77c0d3a1e39fb38f450625cf + + https://github.com/dotnet/runtime + 58efa4b79751a2dad08d9bf7ca67930f8160afe3 + https://github.com/dotnet/runtime 14b34eb02bc8969b77c0d3a1e39fb38f450625cf diff --git a/eng/Versions.props b/eng/Versions.props index d2ac516e10de..4bba8896a949 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -10,6 +10,7 @@ 12.0.100-rc.1.521 6.0.0-rc.1.21417.1 6.0.0-rc.1.21417.1 + 6.0.0-rc.1.21417.1 6.0.0-rc.1.21417.1 6.0.0-rc.1.21417.1 6.0.0-rc.1.21417.1 diff --git a/src/BlazorWebView/src/Maui/BlazorWebViewRegistrationExtensions.cs b/src/BlazorWebView/src/Maui/BlazorWebViewRegistrationExtensions.cs index 30ee76f0668e..ad927896205b 100644 --- a/src/BlazorWebView/src/Maui/BlazorWebViewRegistrationExtensions.cs +++ b/src/BlazorWebView/src/Maui/BlazorWebViewRegistrationExtensions.cs @@ -1,18 +1,19 @@ using System; +using Microsoft.Maui; using Microsoft.Maui.Hosting; namespace Microsoft.AspNetCore.Components.WebView.Maui { public static class BlazorWebViewRegistrationExtensions { - public static TAppHostBuilder RegisterBlazorMauiWebView(this TAppHostBuilder appHostBuilder) where TAppHostBuilder : IAppHostBuilder + public static MauiAppBuilder RegisterBlazorMauiWebView(this MauiAppBuilder appHostBuilder) { if (appHostBuilder is null) { throw new ArgumentNullException(nameof(appHostBuilder)); } - appHostBuilder.ConfigureMauiHandlers((_, handlers) => handlers.AddHandler()); + appHostBuilder.ConfigureMauiHandlers(handlers => handlers.AddHandler()); return appHostBuilder; } diff --git a/src/Compatibility/ControlGallery/src/Core/Startup.cs b/src/Compatibility/ControlGallery/src/Core/Startup.cs index 308c1f1dd206..61dd71562ade 100644 --- a/src/Compatibility/ControlGallery/src/Core/Startup.cs +++ b/src/Compatibility/ControlGallery/src/Core/Startup.cs @@ -6,13 +6,14 @@ namespace Microsoft.Maui.Controls.Compatibility.ControlGallery { - public class Startup : IStartup + public static class MauiProgram { internal static bool UseBlazor = false; - public virtual void Configure(IAppHostBuilder appBuilder) + public static MauiAppBuilder CreateAppBuilder() { - appBuilder + var builder = MauiApp.CreateBuilder(); + builder .UseMauiApp() .ConfigureMauiHandlers(handlers => { @@ -26,14 +27,14 @@ public virtual void Configure(IAppHostBuilder appBuilder) { fonts.AddCompatibilityFonts(Device.GetAssemblies()); }) - .ConfigureServices(services => - { - DependencyService.Register(Device.GetAssemblies()); - }) .ConfigureEffects(effects => { effects.AddCompatibilityEffects(Device.GetAssemblies()); }); + + DependencyService.Register(Device.GetAssemblies()); + + return builder; } } } diff --git a/src/Compatibility/ControlGallery/src/WinUI/App.xaml.cs b/src/Compatibility/ControlGallery/src/WinUI/App.xaml.cs index 19e91c85a86c..38b0d670ba6b 100644 --- a/src/Compatibility/ControlGallery/src/WinUI/App.xaml.cs +++ b/src/Compatibility/ControlGallery/src/WinUI/App.xaml.cs @@ -16,6 +16,6 @@ public App() InitializeComponent(); } - protected override IStartup OnCreateStartup() => new WinUIStartup(); + protected override MauiAppBuilder CreateAppBuilder() => WinUIMauiProgram.CreateAppBuilder(); } } diff --git a/src/Compatibility/ControlGallery/src/WinUI/WinUIStartup.cs b/src/Compatibility/ControlGallery/src/WinUI/WinUIStartup.cs index 01e3c0edfd15..43363fc9a5c1 100644 --- a/src/Compatibility/ControlGallery/src/WinUI/WinUIStartup.cs +++ b/src/Compatibility/ControlGallery/src/WinUI/WinUIStartup.cs @@ -1,5 +1,6 @@ using System; using System.Globalization; +using System.Reflection.PortableExecutable; using Microsoft.Maui.Controls.Compatibility.Platform.UWP; using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.Graphics; @@ -15,13 +16,13 @@ namespace Microsoft.Maui.Controls.Compatibility.ControlGallery.WinUI { - public class WinUIStartup : Startup + public class WinUIMauiProgram { - public override void Configure(IAppHostBuilder appBuilder) + public static MauiAppBuilder CreateAppBuilder() { - base.Configure(appBuilder); + var builder = MauiProgram.CreateAppBuilder(); - appBuilder.ConfigureLifecycleEvents(lifecycle => lifecycle + builder.ConfigureLifecycleEvents(lifecycle => lifecycle .AddWindows(windows => windows .OnLaunching((_, e) => { @@ -32,6 +33,8 @@ public override void Configure(IAppHostBuilder appBuilder) } }) .OnActivated(WinUIPageStartup.OnActivated))); + + return builder; } } diff --git a/src/Compatibility/ControlGallery/src/iOS/AppDelegate.cs b/src/Compatibility/ControlGallery/src/iOS/AppDelegate.cs index 7da514d17287..2baef0c1ee73 100644 --- a/src/Compatibility/ControlGallery/src/iOS/AppDelegate.cs +++ b/src/Compatibility/ControlGallery/src/iOS/AppDelegate.cs @@ -6,6 +6,7 @@ using CoreGraphics; using Foundation; using UIKit; +using Microsoft.Maui; using Microsoft.Maui.Controls; using Microsoft.Maui.Controls.Compatibility.ControlGallery.iOS; using Microsoft.Maui.Controls.Compatibility; @@ -100,8 +101,10 @@ public string GetTestCloudDevice() } [Register("AppDelegate")] - public partial class AppDelegate : MauiUIApplicationDelegate + public partial class AppDelegate : MauiUIApplicationDelegate { + protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); + public override bool FinishedLaunching(UIApplication uiApplication, NSDictionary launchOptions) { UISwitch.Appearance.OnTintColor = UIColor.Red; diff --git a/src/Compatibility/Core/src/AppHostBuilderExtensions.Android.cs b/src/Compatibility/Core/src/AppHostBuilderExtensions.Android.cs index 7c89f1fb3538..ac32a1b5b4f0 100644 --- a/src/Compatibility/Core/src/AppHostBuilderExtensions.Android.cs +++ b/src/Compatibility/Core/src/AppHostBuilderExtensions.Android.cs @@ -6,7 +6,7 @@ namespace Microsoft.Maui.Controls.Hosting { public static partial class AppHostBuilderExtensions { - internal static IAppHostBuilder ConfigureCompatibilityLifecycleEvents(this IAppHostBuilder builder) => + internal static MauiAppBuilder ConfigureCompatibilityLifecycleEvents(this MauiAppBuilder builder) => builder.ConfigureLifecycleEvents(events => events.AddAndroid(OnConfigureLifeCycle)); static void OnConfigureLifeCycle(IAndroidLifecycleBuilder android) diff --git a/src/Compatibility/Core/src/AppHostBuilderExtensions.Standard.cs b/src/Compatibility/Core/src/AppHostBuilderExtensions.Standard.cs index f0ac34387ee1..298c043e9681 100644 --- a/src/Compatibility/Core/src/AppHostBuilderExtensions.Standard.cs +++ b/src/Compatibility/Core/src/AppHostBuilderExtensions.Standard.cs @@ -6,7 +6,7 @@ namespace Microsoft.Maui.Controls.Hosting { public static partial class AppHostBuilderExtensions { - internal static IAppHostBuilder ConfigureCompatibilityLifecycleEvents(this IAppHostBuilder builder) => + internal static MauiAppBuilder ConfigureCompatibilityLifecycleEvents(this MauiAppBuilder builder) => builder; } } diff --git a/src/Compatibility/Core/src/AppHostBuilderExtensions.Windows.cs b/src/Compatibility/Core/src/AppHostBuilderExtensions.Windows.cs index 8308f1fb5536..d0d1747efc3e 100644 --- a/src/Compatibility/Core/src/AppHostBuilderExtensions.Windows.cs +++ b/src/Compatibility/Core/src/AppHostBuilderExtensions.Windows.cs @@ -17,7 +17,7 @@ namespace Microsoft.Maui.Controls.Hosting { public static partial class AppHostBuilderExtensions { - internal static IAppHostBuilder ConfigureCompatibilityLifecycleEvents(this IAppHostBuilder builder) => + internal static MauiAppBuilder ConfigureCompatibilityLifecycleEvents(this MauiAppBuilder builder) => builder.ConfigureLifecycleEvents(events => events.AddWindows(OnConfigureLifeCycle)); static void OnConfigureLifeCycle(IWindowsLifecycleBuilder windows) diff --git a/src/Compatibility/Core/src/AppHostBuilderExtensions.cs b/src/Compatibility/Core/src/AppHostBuilderExtensions.cs index aaff7a5ec52d..bea90becd4b1 100644 --- a/src/Compatibility/Core/src/AppHostBuilderExtensions.cs +++ b/src/Compatibility/Core/src/AppHostBuilderExtensions.cs @@ -40,36 +40,25 @@ namespace Microsoft.Maui.Controls.Hosting { - public static partial class AppHostBuilderExtensions + public static class MauiAppBuilderExtensions { - public static IAppHostBuilder UseMauiApp(this IAppHostBuilder builder) + public static MauiAppBuilder UseMauiApp(this MauiAppBuilder builder) where TApp : class, IApplication { - builder.ConfigureServices((context, collection) => - { - collection.AddSingleton(); - }); - + builder.Services.AddSingleton(); builder.SetupDefaults(); - return builder; } - public static IAppHostBuilder UseMauiApp(this IAppHostBuilder builder, Func implementationFactory) + public static MauiAppBuilder UseMauiApp(this MauiAppBuilder builder, Func implementationFactory) where TApp : class, IApplication { - builder.ConfigureServices((context, collection) => - { - collection.AddSingleton(implementationFactory); - }); - + builder.Services.AddSingleton(implementationFactory); builder.SetupDefaults(); - return builder; } - - static IAppHostBuilder ConfigureImageSourceHandlers(this IAppHostBuilder builder) + static MauiAppBuilder ConfigureImageSourceHandlers(this MauiAppBuilder builder) { builder.ConfigureImageSources(services => { @@ -82,7 +71,7 @@ static IAppHostBuilder ConfigureImageSourceHandlers(this IAppHostBuilder builder return builder; } - static IAppHostBuilder SetupDefaults(this IAppHostBuilder builder) + static MauiAppBuilder SetupDefaults(this MauiAppBuilder builder) { builder.ConfigureCompatibilityLifecycleEvents(); builder.ConfigureImageSourceHandlers(); @@ -179,16 +168,30 @@ static IAppHostBuilder SetupDefaults(this IAppHostBuilder builder) // Update the mappings for IView/View to work specifically for Controls VisualElement.RemapForControls(); Label.RemapForControls(); + }); - }) - .ConfigureServices(); + builder.AddMauiCompat(); return builder; } - class MauiCompatBuilder : IMauiServiceBuilder + private static MauiAppBuilder AddMauiCompat(this MauiAppBuilder builder) { - public void Configure(HostBuilderContext context, IServiceProvider services) +#if __IOS__ || MACCATALYST + builder.Services.AddSingleton(NativeGraphicsService.Instance); +#elif __ANDROID__ + builder.Services.AddSingleton(NativeGraphicsService.Instance); +#elif WINDOWS + builder.Services.AddSingleton(W2DGraphicsService.Instance); +#endif + + builder.Services.AddSingleton(); + return builder; + } + + class MauiCompatInitializer : IMauiInitializeService + { + public void Initialize(IServiceProvider services) { #if __ANDROID__ || __IOS__ || WINDOWS || MACCATALYST CompatServiceProvider.SetServiceProvider(services); @@ -216,17 +219,6 @@ public void Configure(HostBuilderContext context, IServiceProvider services) #endif } - public void ConfigureServices(HostBuilderContext context, IServiceCollection services) - { -#if __IOS__ || MACCATALYST - services.AddSingleton(NativeGraphicsService.Instance); -#elif __ANDROID__ - services.AddSingleton(NativeGraphicsService.Instance); -#elif WINDOWS - services.AddSingleton(W2DGraphicsService.Instance); -#endif - } - #if WINDOWS static void AddLibraryResources(string key, string uri) { diff --git a/src/Compatibility/Core/src/AppHostBuilderExtensions.iOS.cs b/src/Compatibility/Core/src/AppHostBuilderExtensions.iOS.cs index b9958f522dc5..1a064d72e303 100644 --- a/src/Compatibility/Core/src/AppHostBuilderExtensions.iOS.cs +++ b/src/Compatibility/Core/src/AppHostBuilderExtensions.iOS.cs @@ -6,7 +6,7 @@ namespace Microsoft.Maui.Controls.Hosting { public static partial class AppHostBuilderExtensions { - internal static IAppHostBuilder ConfigureCompatibilityLifecycleEvents(this IAppHostBuilder builder) => + internal static MauiAppBuilder ConfigureCompatibilityLifecycleEvents(this MauiAppBuilder builder) => builder.ConfigureLifecycleEvents(events => events.AddiOS(OnConfigureLifeCycle)); static void OnConfigureLifeCycle(IiOSLifecycleBuilder iOS) diff --git a/src/Controls/samples/Controls.Sample.Droid/MainApplication.cs b/src/Controls/samples/Controls.Sample.Droid/MainApplication.cs index 4462822737ae..2ac701a4a9e8 100644 --- a/src/Controls/samples/Controls.Sample.Droid/MainApplication.cs +++ b/src/Controls/samples/Controls.Sample.Droid/MainApplication.cs @@ -7,10 +7,12 @@ namespace Maui.Controls.Sample.Droid { [Application] - public class MainApplication : MauiApplication + public class MainApplication : MauiApplication { public MainApplication(IntPtr handle, JniHandleOwnership ownership) : base(handle, ownership) { } + + protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); } -} \ No newline at end of file +} diff --git a/src/Controls/samples/Controls.Sample.MacCatalyst/AppDelegate.cs b/src/Controls/samples/Controls.Sample.MacCatalyst/AppDelegate.cs index 70e3b7ea96d3..96045c90f915 100644 --- a/src/Controls/samples/Controls.Sample.MacCatalyst/AppDelegate.cs +++ b/src/Controls/samples/Controls.Sample.MacCatalyst/AppDelegate.cs @@ -11,7 +11,8 @@ namespace Sample.MacCatalyst { [Register("AppDelegate")] - public class AppDelegate : MauiUIApplicationDelegate + public class AppDelegate : MauiUIApplicationDelegate { + protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); } } \ No newline at end of file diff --git a/src/Controls/samples/Controls.Sample.Profiling/Platforms/Android/MainApplication.cs b/src/Controls/samples/Controls.Sample.Profiling/Platforms/Android/MainApplication.cs index d12d1aea8b30..ae655e667eac 100644 --- a/src/Controls/samples/Controls.Sample.Profiling/Platforms/Android/MainApplication.cs +++ b/src/Controls/samples/Controls.Sample.Profiling/Platforms/Android/MainApplication.cs @@ -6,10 +6,12 @@ namespace Maui.Controls.Sample.Profiling { [Application] - public class MainApplication : MauiApplication + public class MainApplication : MauiApplication { public MainApplication(IntPtr handle, JniHandleOwnership ownership) : base(handle, ownership) { } + + protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); } } \ No newline at end of file diff --git a/src/Controls/samples/Controls.Sample.Profiling/Platforms/MacCatalyst/AppDelegate.cs b/src/Controls/samples/Controls.Sample.Profiling/Platforms/MacCatalyst/AppDelegate.cs index a1cbd96a99f4..e2f60bc805ca 100644 --- a/src/Controls/samples/Controls.Sample.Profiling/Platforms/MacCatalyst/AppDelegate.cs +++ b/src/Controls/samples/Controls.Sample.Profiling/Platforms/MacCatalyst/AppDelegate.cs @@ -4,7 +4,8 @@ namespace Maui.Controls.Sample.Profiling { [Register("AppDelegate")] - public class AppDelegate : MauiUIApplicationDelegate + public class AppDelegate : MauiUIApplicationDelegate { + protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); } } \ No newline at end of file diff --git a/src/Controls/samples/Controls.Sample.Profiling/Platforms/iOS/AppDelegate.cs b/src/Controls/samples/Controls.Sample.Profiling/Platforms/iOS/AppDelegate.cs index a1cbd96a99f4..e2f60bc805ca 100644 --- a/src/Controls/samples/Controls.Sample.Profiling/Platforms/iOS/AppDelegate.cs +++ b/src/Controls/samples/Controls.Sample.Profiling/Platforms/iOS/AppDelegate.cs @@ -4,7 +4,8 @@ namespace Maui.Controls.Sample.Profiling { [Register("AppDelegate")] - public class AppDelegate : MauiUIApplicationDelegate + public class AppDelegate : MauiUIApplicationDelegate { + protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); } } \ No newline at end of file diff --git a/src/Controls/samples/Controls.Sample.Profiling/Startup.cs b/src/Controls/samples/Controls.Sample.Profiling/Startup.cs index a3ae6d507a48..80be80551fc6 100644 --- a/src/Controls/samples/Controls.Sample.Profiling/Startup.cs +++ b/src/Controls/samples/Controls.Sample.Profiling/Startup.cs @@ -7,16 +7,20 @@ namespace Maui.Controls.Sample.Profiling { - public class Startup : IStartup + public static class MauiProgram { - public void Configure(IAppHostBuilder appBuilder) + public static MauiAppBuilder CreateAppBuilder() { + var appBuilder = MauiApp.CreateBuilder(); + appBuilder .UseMauiApp() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); }); + + return appBuilder; } } } diff --git a/src/Controls/samples/Controls.Sample.SingleProject/MainWindow.cs b/src/Controls/samples/Controls.Sample.SingleProject/MainWindow.cs index a62a390aa430..c1f991069987 100644 --- a/src/Controls/samples/Controls.Sample.SingleProject/MainWindow.cs +++ b/src/Controls/samples/Controls.Sample.SingleProject/MainWindow.cs @@ -5,7 +5,7 @@ namespace Maui.Controls.Sample.SingleProject { public class MainWindow : Window { - public MainWindow() : base(Startup.UseBlazor ? new BlazorPage() : new MainPage()) + public MainWindow() : base(MauiProgram.UseBlazor ? new BlazorPage() : new MainPage()) { } } diff --git a/src/Controls/samples/Controls.Sample.SingleProject/Platforms/Android/MainApplication.cs b/src/Controls/samples/Controls.Sample.SingleProject/Platforms/Android/MainApplication.cs index 2e3b3e23ca5d..df51bc5a6fda 100644 --- a/src/Controls/samples/Controls.Sample.SingleProject/Platforms/Android/MainApplication.cs +++ b/src/Controls/samples/Controls.Sample.SingleProject/Platforms/Android/MainApplication.cs @@ -6,10 +6,12 @@ namespace Maui.Controls.Sample.SingleProject { [Application] - public class MainApplication : MauiApplication + public class MainApplication : MauiApplication { public MainApplication(IntPtr handle, JniHandleOwnership ownership) : base(handle, ownership) { } + + protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); } } \ No newline at end of file diff --git a/src/Controls/samples/Controls.Sample.SingleProject/Platforms/MacCatalyst/AppDelegate.cs b/src/Controls/samples/Controls.Sample.SingleProject/Platforms/MacCatalyst/AppDelegate.cs index 96ec576cb749..793221ce315d 100644 --- a/src/Controls/samples/Controls.Sample.SingleProject/Platforms/MacCatalyst/AppDelegate.cs +++ b/src/Controls/samples/Controls.Sample.SingleProject/Platforms/MacCatalyst/AppDelegate.cs @@ -4,7 +4,8 @@ namespace Maui.Controls.Sample.SingleProject { [Register("AppDelegate")] - public class AppDelegate : MauiUIApplicationDelegate + public class AppDelegate : MauiUIApplicationDelegate { + protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); } } \ No newline at end of file diff --git a/src/Controls/samples/Controls.Sample.SingleProject/Platforms/Windows/App.xaml.cs b/src/Controls/samples/Controls.Sample.SingleProject/Platforms/Windows/App.xaml.cs index a52fe031f12b..8c044d05cabf 100644 --- a/src/Controls/samples/Controls.Sample.SingleProject/Platforms/Windows/App.xaml.cs +++ b/src/Controls/samples/Controls.Sample.SingleProject/Platforms/Windows/App.xaml.cs @@ -22,7 +22,8 @@ public App() } } - public class MiddleApp : MauiWinUIApplication + public class MiddleApp : MauiWinUIApplication { - } + protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); + } } diff --git a/src/Controls/samples/Controls.Sample.SingleProject/Platforms/iOS/AppDelegate.cs b/src/Controls/samples/Controls.Sample.SingleProject/Platforms/iOS/AppDelegate.cs index 96ec576cb749..793221ce315d 100644 --- a/src/Controls/samples/Controls.Sample.SingleProject/Platforms/iOS/AppDelegate.cs +++ b/src/Controls/samples/Controls.Sample.SingleProject/Platforms/iOS/AppDelegate.cs @@ -4,7 +4,8 @@ namespace Maui.Controls.Sample.SingleProject { [Register("AppDelegate")] - public class AppDelegate : MauiUIApplicationDelegate + public class AppDelegate : MauiUIApplicationDelegate { + protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); } } \ No newline at end of file diff --git a/src/Controls/samples/Controls.Sample.SingleProject/Startup.cs b/src/Controls/samples/Controls.Sample.SingleProject/Startup.cs index 1ba1c1d6dae6..905e161a10e2 100644 --- a/src/Controls/samples/Controls.Sample.SingleProject/Startup.cs +++ b/src/Controls/samples/Controls.Sample.SingleProject/Startup.cs @@ -1,31 +1,27 @@ using Microsoft.Maui; -using Microsoft.Maui.Controls.Compatibility; -using Microsoft.Maui.Hosting; using Microsoft.AspNetCore.Components.WebView.Maui; using Microsoft.Extensions.DependencyInjection; using Microsoft.Maui.Controls.Hosting; namespace Maui.Controls.Sample.SingleProject { - public class Startup : IStartup + public static class MauiProgram { internal static bool UseBlazor = false; - public void Configure(IAppHostBuilder appBuilder) + public static MauiAppBuilder CreateAppBuilder() { + var appBuilder = MauiApp.CreateBuilder(); appBuilder - .RegisterBlazorMauiWebView() .UseMauiApp(); if (UseBlazor) - { - appBuilder.UseMicrosoftExtensionsServiceProviderFactory(); // Blazor requires service scopes, which are supported only with Microsoft.Extensions.DependencyInjection - appBuilder - .ConfigureServices(services => - { - services.AddBlazorWebView(); - }); + { + appBuilder.RegisterBlazorMauiWebView(); + appBuilder.Services.AddBlazorWebView(); } + + return appBuilder; } } } diff --git a/src/Controls/samples/Controls.Sample.WinUI/App.xaml.cs b/src/Controls/samples/Controls.Sample.WinUI/App.xaml.cs index 874b0fc54006..ab8887b1cbf9 100644 --- a/src/Controls/samples/Controls.Sample.WinUI/App.xaml.cs +++ b/src/Controls/samples/Controls.Sample.WinUI/App.xaml.cs @@ -9,6 +9,6 @@ public App() InitializeComponent(); } - protected override IStartup OnCreateStartup() => new Startup(); + protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); } } \ No newline at end of file diff --git a/src/Controls/samples/Controls.Sample.iOS/AppDelegate.cs b/src/Controls/samples/Controls.Sample.iOS/AppDelegate.cs index cfcc70970938..a7f694fc4a29 100644 --- a/src/Controls/samples/Controls.Sample.iOS/AppDelegate.cs +++ b/src/Controls/samples/Controls.Sample.iOS/AppDelegate.cs @@ -4,7 +4,8 @@ namespace Maui.Controls.Sample.iOS { [Register("AppDelegate")] - public class AppDelegate : MauiUIApplicationDelegate + public class AppDelegate : MauiUIApplicationDelegate { + protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); } } \ No newline at end of file diff --git a/src/Controls/samples/Controls.Sample/Controls/BordelessEntry/BordelessEntryAppHostBuilderExtensions.cs b/src/Controls/samples/Controls.Sample/Controls/BordelessEntry/BordelessEntryAppHostBuilderExtensions.cs index a864244d7e44..cb62e90351ec 100644 --- a/src/Controls/samples/Controls.Sample/Controls/BordelessEntry/BordelessEntryAppHostBuilderExtensions.cs +++ b/src/Controls/samples/Controls.Sample/Controls/BordelessEntry/BordelessEntryAppHostBuilderExtensions.cs @@ -1,13 +1,21 @@ using System; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Maui; using Microsoft.Maui.Hosting; +using static Microsoft.Maui.Essentials.EssentialsExtensions; namespace Maui.Controls.Sample.Controls { static class BordelessEntryAppHostBuilderExtensions { - public static IAppHostBuilder UseBordelessEntry(this IAppHostBuilder builder, Action configureDelegate = null) + public static MauiAppBuilder UseBordelessEntry(this MauiAppBuilder builder, Action configureDelegate = null) { - builder.ConfigureServices((ctx, red) => configureDelegate?.Invoke(red)); + builder.Services.AddSingleton(); + + if (configureDelegate != null) + { + builder.Services.AddSingleton(new BorderlessEntryRegistration(configureDelegate)); + } return builder; } diff --git a/src/Controls/samples/Controls.Sample/Controls/BordelessEntry/BordelessEntryServiceBuilder.cs b/src/Controls/samples/Controls.Sample/Controls/BordelessEntry/BordelessEntryServiceBuilder.cs index 468dc71bdca0..3bfd555225c4 100644 --- a/src/Controls/samples/Controls.Sample/Controls/BordelessEntry/BordelessEntryServiceBuilder.cs +++ b/src/Controls/samples/Controls.Sample/Controls/BordelessEntry/BordelessEntryServiceBuilder.cs @@ -7,10 +7,25 @@ namespace Maui.Controls.Sample.Controls { - class BordelessEntryServiceBuilder : IMauiServiceBuilder + internal class BorderlessEntryRegistration { - static IMauiHandlersCollection HandlersCollection; - static readonly Dictionary PendingHandlers = new(); + private readonly Action _builderAction; + + public BorderlessEntryRegistration(Action builderAction) + { + _builderAction = builderAction; + } + + internal void RunBuilderAction(BordelessEntryServiceBuilder builder) + { + _builderAction(builder); + } + } + + class BordelessEntryServiceBuilder + { + internal static IMauiHandlersCollection HandlersCollection; + internal static readonly Dictionary PendingHandlers = new(); public static void TryAddHandler() where TType : IView @@ -21,21 +36,35 @@ public static void TryAddHandler() else HandlersCollection.TryAddHandler(); } + } + + class BorderlessEntryInitializer : IMauiInitializeService + { + private readonly IEnumerable _borderlessEntryRegistrations; - void IMauiServiceBuilder.ConfigureServices(HostBuilderContext context, IServiceCollection services) + public BorderlessEntryInitializer(IEnumerable borderlessEntryRegistrations) { - // No-op + _borderlessEntryRegistrations = borderlessEntryRegistrations; } - void IMauiServiceBuilder.Configure(HostBuilderContext context, IServiceProvider services) + public void Initialize(IServiceProvider services) { - HandlersCollection ??= services.GetRequiredService().GetCollection(); + var essentialsBuilder = new BordelessEntryServiceBuilder(); + if (_borderlessEntryRegistrations != null) + { + foreach (var essentialsRegistration in _borderlessEntryRegistrations) + { + essentialsRegistration.RunBuilderAction(essentialsBuilder); + } + } + + BordelessEntryServiceBuilder.HandlersCollection ??= services.GetRequiredService().GetCollection(); - if (PendingHandlers.Count > 0) + if (BordelessEntryServiceBuilder.PendingHandlers.Count > 0) { - HandlersCollection.TryAddHandlers(PendingHandlers); - PendingHandlers.Clear(); + BordelessEntryServiceBuilder.HandlersCollection.TryAddHandlers(BordelessEntryServiceBuilder.PendingHandlers); + BordelessEntryServiceBuilder.PendingHandlers.Clear(); } } } -} \ No newline at end of file +} diff --git a/src/Controls/samples/Controls.Sample/Extensions/EssentialsExtensions.cs b/src/Controls/samples/Controls.Sample/Extensions/EssentialsExtensions.cs index 0a3fd4ad913c..26b43a38dd0e 100644 --- a/src/Controls/samples/Controls.Sample/Extensions/EssentialsExtensions.cs +++ b/src/Controls/samples/Controls.Sample/Extensions/EssentialsExtensions.cs @@ -10,18 +10,14 @@ namespace Microsoft.Maui.Essentials { public static class EssentialsExtensions { - public static IAppHostBuilder ConfigureEssentials(this IAppHostBuilder builder, Action configureDelegate = null) + public static MauiAppBuilder ConfigureEssentials(this MauiAppBuilder builder, Action configureDelegate = null) { - if (configureDelegate == null) - builder.ConfigureEssentials((Action)null); - else - builder.ConfigureEssentials((_, essentials) => configureDelegate(essentials)); - - return builder; - } + if (configureDelegate != null) + { + builder.Services.AddSingleton(new EssentialsRegistration(configureDelegate)); + } + builder.Services.AddSingleton(); - public static IAppHostBuilder ConfigureEssentials(this IAppHostBuilder builder, Action configureDelegate = null) - { builder.ConfigureLifecycleEvents(life => { #if __ANDROID__ @@ -63,73 +59,59 @@ public static IAppHostBuilder ConfigureEssentials(this IAppHostBuilder builder, #endif }); - if (configureDelegate != null) - builder.ConfigureServices(configureDelegate); - return builder; } public static IEssentialsBuilder AddAppAction(this IEssentialsBuilder essentials, string id, string title, string subtitle = null, string icon = null) => essentials.AddAppAction(new AppAction(id, title, subtitle, icon)); - class EssentialsBuilder : IEssentialsBuilder, IMauiServiceBuilder + internal class EssentialsRegistration { - readonly List _appActions = new List(); - Action _appActionHandlers; - bool _trackVersions; + private readonly Action _registerEssentials; -#pragma warning disable CS0414 // Remove unread private members - bool _useLegaceSecureStorage; - string _mapServiceToken; -#pragma warning restore CS0414 // Remove unread private members - - public IEssentialsBuilder UseMapServiceToken(string token) + public EssentialsRegistration(Action registerEssentials) { - _mapServiceToken = token; - return this; + _registerEssentials = registerEssentials; } - public IEssentialsBuilder AddAppAction(AppAction appAction) + internal void RegisterEssentialsOptions(IEssentialsBuilder essentials) { - _appActions.Add(appAction); - return this; - } - - public IEssentialsBuilder OnAppAction(Action action) - { - _appActionHandlers += action; - return this; + _registerEssentials(essentials); } + } - public IEssentialsBuilder UseVersionTracking() - { - _trackVersions = true; - return this; - } + class EssentialsInitializer : IMauiInitializeService + { + private readonly IEnumerable _essentialsRegistrations; + private EssentialsBuilder _essentialsBuilder; - public IEssentialsBuilder UseLegacySecureStorage() + public EssentialsInitializer(IEnumerable essentialsRegistrations) { - _useLegaceSecureStorage = true; - return this; + _essentialsRegistrations = essentialsRegistrations; } - public void ConfigureServices(HostBuilderContext context, IServiceCollection services) + public async void Initialize(IServiceProvider services) { - } + _essentialsBuilder = new EssentialsBuilder(); + if (_essentialsRegistrations != null) + { + foreach (var essentialsRegistration in _essentialsRegistrations) + { + essentialsRegistration.RegisterEssentialsOptions(_essentialsBuilder); + } + } - public async void Configure(HostBuilderContext context, IServiceProvider services) - { #if WINDOWS - Platform.MapServiceToken = _mapServiceToken; + Platform.MapServiceToken = _essentialsBuilder.MapServiceToken; #elif __ANDROID__ - SecureStorage.LegacyKeyHashFallback = _useLegaceSecureStorage; + SecureStorage.LegacyKeyHashFallback = _essentialsBuilder.UseLegaceSecureStorage; #endif AppActions.OnAppAction += HandleOnAppAction; try { - await AppActions.SetAsync(_appActions); + await AppActions.SetAsync(_essentialsBuilder.AppActions); } catch (FeatureNotSupportedException ex) { @@ -138,13 +120,55 @@ public async void Configure(HostBuilderContext context, IServiceProvider service .LogError(ex, "App Actions are not supported on this platform."); } - if (_trackVersions) + if (_essentialsBuilder.TrackVersions) VersionTracking.Track(); } void HandleOnAppAction(object sender, AppActionEventArgs e) { - _appActionHandlers?.Invoke(e.AppAction); + _essentialsBuilder.AppActionHandlers?.Invoke(e.AppAction); + } + } + + class EssentialsBuilder : IEssentialsBuilder + { + internal readonly List AppActions = new List(); + internal Action AppActionHandlers; + internal bool TrackVersions; + +#pragma warning disable CS0414 // Remove unread private members + internal bool UseLegaceSecureStorage; + internal string MapServiceToken; +#pragma warning restore CS0414 // Remove unread private members + + public IEssentialsBuilder UseMapServiceToken(string token) + { + MapServiceToken = token; + return this; + } + + public IEssentialsBuilder AddAppAction(AppAction appAction) + { + AppActions.Add(appAction); + return this; + } + + public IEssentialsBuilder OnAppAction(Action action) + { + AppActionHandlers += action; + return this; + } + + public IEssentialsBuilder UseVersionTracking() + { + TrackVersions = true; + return this; + } + + public IEssentialsBuilder UseLegacySecureStorage() + { + UseLegaceSecureStorage = true; + return this; } } } diff --git a/src/Controls/samples/Controls.Sample/Startup.cs b/src/Controls/samples/Controls.Sample/Startup.cs index 91b91498256c..02f4a68ce0e8 100644 --- a/src/Controls/samples/Controls.Sample/Startup.cs +++ b/src/Controls/samples/Controls.Sample/Startup.cs @@ -24,14 +24,17 @@ namespace Maui.Controls.Sample { public class CustomButton : Button { } - public class Startup : IStartup + public static class MauiProgram { enum PageType { Main, Blazor, Shell, Template } - readonly PageType _pageType = PageType.Main; + readonly static PageType _pageType = PageType.Main; - public void Configure(IAppHostBuilder appBuilder) + public static MauiAppBuilder CreateAppBuilder() { + var appBuilder = MauiApp.CreateBuilder(); + appBuilder.UseMauiApp(); + var services = appBuilder.Services; appBuilder .ConfigureMauiHandlers(handlers => @@ -48,7 +51,6 @@ public void Configure(IAppHostBuilder appBuilder) #endif }); - // Use a "third party" library that brings in a massive amount of controls appBuilder.UseBordelessEntry(); appBuilder.ConfigureEffects(builder => @@ -60,41 +62,34 @@ public void Configure(IAppHostBuilder appBuilder) appBuilder.EnableHotReload(); #endif - appBuilder - .ConfigureAppConfiguration(config => - { - config.AddInMemoryCollection(new Dictionary + appBuilder.Configuration.AddInMemoryCollection( + new Dictionary { {"MyKey", "Dictionary MyKey Value"}, {":Title", "Dictionary_Title"}, {"Position:Name", "Dictionary_Name" }, {"Logging:LogLevel:Default", "Warning"} }); - }); #if NET6_0_OR_GREATER appBuilder .RegisterBlazorMauiWebView(); + services.AddBlazorWebView(); #endif - appBuilder - .ConfigureServices(services => - { - services.AddLogging(logging => - { + services.AddLogging(logging => + { #if WINDOWS - logging.AddDebug(); + logging.AddDebug(); #else - logging.AddConsole(); + logging.AddConsole(); #endif - }); + }); - services.AddSingleton(); - services.AddTransient(); + services.AddSingleton(); + services.AddTransient(); -#if NET6_0_OR_GREATER - services.AddBlazorWebView(); -#endif + services.AddTransient(); services.AddTransient( serviceType: typeof(Page), @@ -112,8 +107,7 @@ public void Configure(IAppHostBuilder appBuilder) _ => throw new Exception(), }); - services.AddTransient(); - }) + appBuilder .ConfigureFonts(fonts => { fonts.AddFont("Dokdo-Regular.ttf", "Dokdo"); @@ -218,6 +212,8 @@ static bool LogEvent(string eventName, string type = null) return true; } }); + + return appBuilder; } } } \ No newline at end of file diff --git a/src/Controls/src/Core/Controls.Core-net6.csproj b/src/Controls/src/Core/Controls.Core-net6.csproj index 1e9b50e3a9ff..75d5d3b9b772 100644 --- a/src/Controls/src/Core/Controls.Core-net6.csproj +++ b/src/Controls/src/Core/Controls.Core-net6.csproj @@ -21,6 +21,15 @@ + + + + + + + + + $(TargetsForTfmSpecificBuildOutput); diff --git a/src/Controls/src/Core/Controls.Core.csproj b/src/Controls/src/Core/Controls.Core.csproj index b3a52e955da0..35590f3cad30 100644 --- a/src/Controls/src/Core/Controls.Core.csproj +++ b/src/Controls/src/Core/Controls.Core.csproj @@ -32,6 +32,14 @@ + + + + + + + + high diff --git a/src/Controls/src/Core/Hosting/Effects/AppHostBuilderExtensions.cs b/src/Controls/src/Core/Hosting/Effects/AppHostBuilderExtensions.cs index 4bb6e931ea2e..5c12e60cc505 100644 --- a/src/Controls/src/Core/Hosting/Effects/AppHostBuilderExtensions.cs +++ b/src/Controls/src/Core/Hosting/Effects/AppHostBuilderExtensions.cs @@ -1,74 +1,86 @@ using System; using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; using Microsoft.Maui.Controls.Internals; using Microsoft.Maui.Controls.Platform; -using Microsoft.Maui.Hosting; namespace Microsoft.Maui.Controls.Hosting { public static partial class AppHostBuilderExtensions { - public static IAppHostBuilder ConfigureEffects(this IAppHostBuilder builder, Action configureDelegate) + public static MauiAppBuilder ConfigureEffects(this MauiAppBuilder builder, Action configureDelegate) { - builder.ConfigureServices(b => configureDelegate(b)); + builder.Services.AddSingleton(); + builder.Services.AddSingleton(new EffectsRegistration(configureDelegate)); + return builder; } + } + + internal class EffectsRegistration + { + private readonly Action _registerEffects; - class EffectCollectionBuilder : IMauiServiceBuilder, IEffectsBuilder + public EffectsRegistration(Action registerEffects) { - internal Dictionary> RegisteredEffects { get; } = new Dictionary>(); + _registerEffects = registerEffects; + } - public void ConfigureServices(HostBuilderContext context, IServiceCollection services) - { - services.AddSingleton(); - } + internal void AddEffects(IEffectsBuilder effects) + { + _registerEffects(effects); + } + } - public void Configure(HostBuilderContext context, IServiceProvider services) - { - var effectsProvider = services.GetRequiredService(); - effectsProvider.SetRegisteredEffects(RegisteredEffects); - } + internal class EffectCollectionBuilder : IEffectsBuilder + { + internal Dictionary> RegisteredEffects { get; } = new Dictionary>(); - public IEffectsBuilder Add() - where TEffect : RoutingEffect - where TPlatformEffect : PlatformEffect, new() + public IEffectsBuilder Add() + where TEffect : RoutingEffect + where TPlatformEffect : PlatformEffect, new() + { + RegisteredEffects.Add(typeof(TEffect), () => { - RegisteredEffects.Add(typeof(TEffect), () => - { - if (DependencyResolver.Resolve(typeof(TPlatformEffect)) is TPlatformEffect pe) - return pe; + if (DependencyResolver.Resolve(typeof(TPlatformEffect)) is TPlatformEffect pe) + return pe; - return new TPlatformEffect(); - }); - return this; - } + return new TPlatformEffect(); + }); + return this; + } - public IEffectsBuilder Add(Type TEffect, Type TPlatformEffect) + public IEffectsBuilder Add(Type TEffect, Type TPlatformEffect) + { + RegisteredEffects.Add(TEffect, () => { - RegisteredEffects.Add(TEffect, () => - { - return (PlatformEffect)DependencyResolver.ResolveOrCreate(TPlatformEffect); - }); + return (PlatformEffect)DependencyResolver.ResolveOrCreate(TPlatformEffect); + }); - return this; - } + return this; } } internal class EffectsFactory { - Dictionary> _registeredEffects; + private readonly Dictionary> _registeredEffects; - internal void SetRegisteredEffects(Dictionary> registeredEffects) + public EffectsFactory(IEnumerable effectsRegistrations) { - _registeredEffects = registeredEffects; + if (effectsRegistrations != null) + { + var effectsBuilder = new EffectCollectionBuilder(); + foreach (var effectRegistration in effectsRegistrations) + { + effectRegistration.AddEffects(effectsBuilder); + } + _registeredEffects = effectsBuilder.RegisteredEffects; + } } internal PlatformEffect CreateEffect(Effect fromEffect) { - if (_registeredEffects.TryGetValue(fromEffect.GetType(), out Func effectType)) + if (_registeredEffects != null && _registeredEffects.TryGetValue(fromEffect.GetType(), out Func effectType)) { return effectType(); } diff --git a/src/Controls/tests/Core.UnitTests/HostBuilderAppTests.cs b/src/Controls/tests/Core.UnitTests/HostBuilderAppTests.cs index 42719bc4f72b..9d4756a9f551 100644 --- a/src/Controls/tests/Core.UnitTests/HostBuilderAppTests.cs +++ b/src/Controls/tests/Core.UnitTests/HostBuilderAppTests.cs @@ -1,10 +1,5 @@ using Microsoft.Extensions.DependencyInjection; -using Microsoft.Maui.Controls; -using Microsoft.Maui.Controls.Core; using Microsoft.Maui.Controls.Hosting; -using Microsoft.Maui.Handlers; -using Microsoft.Maui.Hosting; -using NUnit; using NUnit.Framework; namespace Microsoft.Maui.Controls.Core.UnitTests @@ -15,34 +10,34 @@ public class HostBuilderAppTests [Test] public void UseMauiAppRegistersApp() { - var host = new AppHostBuilder() + var mauiApp = MauiApp.CreateBuilder() .UseMauiApp() .Build(); - var app = (ApplicationStub)host.Services.GetRequiredService(); + var app = (ApplicationStub)mauiApp.Services.GetRequiredService(); Assert.AreEqual("Default", app.Property); } [Test] public void UseMauiAppRegistersAppWithFactory() { - var host = new AppHostBuilder() + var mauiApp = MauiApp.CreateBuilder() .UseMauiApp(services => new ApplicationStub { Property = "Factory" }) .Build(); - var app = (ApplicationStub)host.Services.GetRequiredService(); + var app = (ApplicationStub)mauiApp.Services.GetRequiredService(); Assert.AreEqual("Factory", app.Property); } [Test] public void UseMauiAppRegistersSingleton() { - var host = new AppHostBuilder() + var mauiApp = MauiApp.CreateBuilder() .UseMauiApp() .Build(); - var app1 = host.Services.GetRequiredService(); - var app2 = host.Services.GetRequiredService(); + var app1 = mauiApp.Services.GetRequiredService(); + var app2 = mauiApp.Services.GetRequiredService(); Assert.AreEqual(app1, app2); } diff --git a/src/Controls/tests/Core.UnitTests/HostBuilderHandlerTests.cs b/src/Controls/tests/Core.UnitTests/HostBuilderHandlerTests.cs index a2aabaf0617a..438fc82d85b5 100644 --- a/src/Controls/tests/Core.UnitTests/HostBuilderHandlerTests.cs +++ b/src/Controls/tests/Core.UnitTests/HostBuilderHandlerTests.cs @@ -1,10 +1,7 @@ using Microsoft.Extensions.DependencyInjection; -using Microsoft.Maui.Controls; -using Microsoft.Maui.Controls.Core; using Microsoft.Maui.Controls.Hosting; using Microsoft.Maui.Handlers; using Microsoft.Maui.Hosting; -using NUnit; using NUnit.Framework; namespace Microsoft.Maui.Controls.Core.UnitTests @@ -15,11 +12,14 @@ public class HostBuilderHandlerTests [Test] public void DefaultHandlersAreRegistered() { - var host = new AppHostBuilder() + var mauiApp = MauiApp.CreateBuilder() .UseMauiApp() .Build(); - var handler = host.Handlers.GetHandler(typeof(Button)); + Assert.NotNull(mauiApp.Services); + var handlers = mauiApp.Services.GetRequiredService(); + Assert.NotNull(handlers); + var handler = handlers.GetHandler(typeof(Button)); Assert.NotNull(handler); Assert.AreEqual(handler.GetType(), typeof(ButtonHandler)); @@ -28,12 +28,16 @@ public void DefaultHandlersAreRegistered() [Test] public void CanSpecifyHandler() { - var host = new AppHostBuilder() + var mauiApp = MauiApp.CreateBuilder() .UseMauiApp() - .ConfigureMauiHandlers((_, handlers) => handlers.AddHandler()) + .ConfigureMauiHandlers(handlers => handlers.AddHandler()) .Build(); - var specificHandler = host.Handlers.GetHandler(typeof(Button)); + Assert.NotNull(mauiApp.Services); + var handlers = mauiApp.Services.GetRequiredService(); + Assert.NotNull(handlers); + + var specificHandler = handlers.GetHandler(typeof(Button)); Assert.NotNull(specificHandler); Assert.AreEqual(specificHandler.GetType(), typeof(ButtonHandlerStub)); diff --git a/src/Core/src/Core-net6.csproj b/src/Core/src/Core-net6.csproj index 4deb2418348a..3aba3dec012c 100644 --- a/src/Core/src/Core-net6.csproj +++ b/src/Core/src/Core-net6.csproj @@ -14,7 +14,9 @@ + + diff --git a/src/Core/src/Core.csproj b/src/Core/src/Core.csproj index 2471bf934630..c2438863b939 100644 --- a/src/Core/src/Core.csproj +++ b/src/Core/src/Core.csproj @@ -8,8 +8,10 @@ - + + + diff --git a/src/Core/src/Core/BootstrapHostBuilder.cs b/src/Core/src/Core/BootstrapHostBuilder.cs new file mode 100644 index 000000000000..3bfdb4ae249b --- /dev/null +++ b/src/Core/src/Core/BootstrapHostBuilder.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace Microsoft.Maui +{ + // This exists solely to bootstrap the configuration + internal class BootstrapHostBuilder : IHostBuilder + { + private readonly IServiceCollection _services; + private readonly List> _configureHostActions = new(); + private readonly List> _configureAppActions = new(); + private readonly List> _configureServicesActions = new(); + + private readonly List> _remainingOperations = new(); + + public BootstrapHostBuilder(IServiceCollection services, IDictionary properties) + { + _services = services; + + Properties = properties; + } + + public IDictionary Properties { get; } + + public IHost Build() + { + // HostingHostBuilderExtensions.ConfigureDefaults should never call this. + throw new InvalidOperationException(); + } + + public IHostBuilder ConfigureAppConfiguration(Action configureDelegate) + { + _configureAppActions.Add(configureDelegate ?? throw new ArgumentNullException(nameof(configureDelegate))); + return this; + } + + public IHostBuilder ConfigureContainer(Action configureDelegate) + { + // This is not called by HostingHostBuilderExtensions.ConfigureDefaults currently, but that could change in the future. + // If this does get called in the future, it should be called again at a later stage on the ConfigureHostBuilder. + if (configureDelegate is null) + { + throw new ArgumentNullException(nameof(configureDelegate)); + } + + _remainingOperations.Add(hostBuilder => hostBuilder.ConfigureContainer(configureDelegate)); + return this; + } + + public IHostBuilder ConfigureHostConfiguration(Action configureDelegate) + { + _configureHostActions.Add(configureDelegate ?? throw new ArgumentNullException(nameof(configureDelegate))); + return this; + } + + public IHostBuilder ConfigureServices(Action configureDelegate) + { + // HostingHostBuilderExtensions.ConfigureDefaults calls this via ConfigureLogging + _configureServicesActions.Add(configureDelegate ?? throw new ArgumentNullException(nameof(configureDelegate))); + return this; + } + + public IHostBuilder UseServiceProviderFactory(IServiceProviderFactory factory) where TContainerBuilder : notnull + { + // This is not called by HostingHostBuilderExtensions.ConfigureDefaults currently, but that could change in the future. + // If this does get called in the future, it should be called again at a later stage on the ConfigureHostBuilder. + if (factory is null) + { + throw new ArgumentNullException(nameof(factory)); + } + + _remainingOperations.Add(hostBuilder => hostBuilder.UseServiceProviderFactory(factory)); + return this; + } + + public IHostBuilder UseServiceProviderFactory(Func> factory) where TContainerBuilder : notnull + { + // HostingHostBuilderExtensions.ConfigureDefaults calls this via UseDefaultServiceProvider + // during the initial config stage. It should be called again later on the ConfigureHostBuilder. + if (factory is null) + { + throw new ArgumentNullException(nameof(factory)); + } + + _remainingOperations.Add(hostBuilder => hostBuilder.UseServiceProviderFactory(factory)); + return this; + } + + public HostBuilderContext RunDefaultCallbacks(ConfigurationManager configuration, HostBuilder innerBuilder) + { + var hostConfiguration = new ConfigurationManager(); + + foreach (var configureHostAction in _configureHostActions) + { + configureHostAction(hostConfiguration); + } + + // This is the hosting environment based on configuration we've seen so far. + var hostingEnvironment = new HostingEnvironment() + { + ApplicationName = hostConfiguration[HostDefaults.ApplicationKey], + EnvironmentName = hostConfiguration[HostDefaults.EnvironmentKey] ?? Environments.Production, + ContentRootPath = HostingEnvironment.ResolveContentRootPath(hostConfiguration[HostDefaults.ContentRootKey], AppContext.BaseDirectory), + }; + + hostingEnvironment.ContentRootFileProvider = new PhysicalFileProvider(hostingEnvironment.ContentRootPath); + + var hostContext = new HostBuilderContext(Properties) + { + Configuration = hostConfiguration, + HostingEnvironment = hostingEnvironment, + }; + + // Split the host configuration and app configuration so that the + // subsequent callback don't get a chance to modify the host configuration. + configuration.SetBasePath(hostingEnvironment.ContentRootPath); + + // Chain the host configuration and app configuration together. + configuration.AddConfiguration(hostConfiguration, shouldDisposeConfiguration: true); + + // ConfigureAppConfiguration cannot modify the host configuration because doing so could + // change the environment, content root and application name which is not allowed at this stage. + foreach (var configureAppAction in _configureAppActions) + { + configureAppAction(hostContext, configuration); + } + + // Update the host context, everything from here sees the final + // app configuration + hostContext.Configuration = configuration; + + foreach (var configureServicesAction in _configureServicesActions) + { + configureServicesAction(hostContext, _services); + } + + foreach (var callback in _remainingOperations) + { + callback(innerBuilder); + } + + return hostContext; + } + + private class HostingEnvironment : IHostEnvironment + { + public string EnvironmentName { get; set; } = default!; + public string ApplicationName { get; set; } = default!; + public string ContentRootPath { get; set; } = default!; + public IFileProvider ContentRootFileProvider { get; set; } = default!; + + public static string ResolveContentRootPath(string contentRootPath, string basePath) + { + if (string.IsNullOrEmpty(contentRootPath)) + { + return basePath; + } + if (Path.IsPathRooted(contentRootPath)) + { + return contentRootPath; + } + return Path.Combine(Path.GetFullPath(basePath), contentRootPath); + } + } + } +} diff --git a/src/Core/src/Core/ConfigureHostBuilder.cs b/src/Core/src/Core/ConfigureHostBuilder.cs new file mode 100644 index 000000000000..39a1826ba85a --- /dev/null +++ b/src/Core/src/Core/ConfigureHostBuilder.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace Microsoft.Maui +{ + /// + /// A non-buildable for . + /// Use to build the . + /// + public sealed class ConfigureHostBuilder : IHostBuilder + { + private readonly ConfigurationManager _configuration; + private readonly IServiceCollection _services; + private readonly HostBuilderContext _context; + + private readonly List> _operations = new(); + + internal ConfigureHostBuilder(HostBuilderContext context, ConfigurationManager configuration, IServiceCollection services) + { + _configuration = configuration; + _services = services; + _context = context; + } + + /// + public IDictionary Properties => _context.Properties; + + IHost IHostBuilder.Build() + { + throw new NotSupportedException($"Call {nameof(MauiAppBuilder)}.{nameof(MauiAppBuilder.Build)}() instead."); + } + + /// + public IHostBuilder ConfigureAppConfiguration(Action configureDelegate) + { + // Run these immediately so that they are observable by the imperative code + configureDelegate(_context, _configuration); + return this; + } + + /// + public IHostBuilder ConfigureContainer(Action configureDelegate) + { + if (configureDelegate is null) + { + throw new ArgumentNullException(nameof(configureDelegate)); + } + + _operations.Add(b => b.ConfigureContainer(configureDelegate)); + return this; + } + + /// + public IHostBuilder ConfigureHostConfiguration(Action configureDelegate) + { + var previousApplicationName = _configuration[HostDefaults.ApplicationKey]; + var previousContentRoot = _configuration[HostDefaults.ContentRootKey]; + var previousEnvironment = _configuration[HostDefaults.EnvironmentKey]; + + // Run these immediately so that they are observable by the imperative code + configureDelegate(_configuration); + + // Disallow changing any host settings this late in the cycle, the reasoning is that we've already loaded the default configuration + // and done other things based on environment name, application name or content root. + if (!string.Equals(previousApplicationName, _configuration[HostDefaults.ApplicationKey], StringComparison.OrdinalIgnoreCase)) + { + throw new NotSupportedException("The application name changed. Changing the host configuration is not supported"); + } + + if (!string.Equals(previousContentRoot, _configuration[HostDefaults.ContentRootKey], StringComparison.OrdinalIgnoreCase)) + { + throw new NotSupportedException("The content root changed. Changing the host configuration is not supported"); + } + + if (!string.Equals(previousEnvironment, _configuration[HostDefaults.EnvironmentKey], StringComparison.OrdinalIgnoreCase)) + { + throw new NotSupportedException("The environment changed. Changing the host configuration is not supported"); + } + + return this; + } + + /// + public IHostBuilder ConfigureServices(Action configureDelegate) + { + // Run these immediately so that they are observable by the imperative code + configureDelegate(_context, _services); + return this; + } + + /// + public IHostBuilder UseServiceProviderFactory(IServiceProviderFactory factory) where TContainerBuilder : notnull + { + if (factory is null) + { + throw new ArgumentNullException(nameof(factory)); + } + + _operations.Add(b => b.UseServiceProviderFactory(factory)); + return this; + } + + /// + public IHostBuilder UseServiceProviderFactory(Func> factory) where TContainerBuilder : notnull + { + if (factory is null) + { + throw new ArgumentNullException(nameof(factory)); + } + + _operations.Add(b => b.UseServiceProviderFactory(factory)); + return this; + } + + internal void RunDeferredCallbacks(IHostBuilder hostBuilder) + { + foreach (var operation in _operations) + { + operation(hostBuilder); + } + } + } +} diff --git a/src/Core/src/Core/FontsMauiAppBuilderExtensions.cs b/src/Core/src/Core/FontsMauiAppBuilderExtensions.cs new file mode 100644 index 000000000000..45cafbe10868 --- /dev/null +++ b/src/Core/src/Core/FontsMauiAppBuilderExtensions.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Maui.Hosting; +using Microsoft.Maui.Hosting.Internal; + +namespace Microsoft.Maui +{ + public static class FontsMauiAppBuilderExtensions + { + public static MauiAppBuilder ConfigureFonts(this MauiAppBuilder builder) + { + builder.ConfigureFonts(configureDelegate: null); + return builder; + } + + public static MauiAppBuilder ConfigureFonts(this MauiAppBuilder builder, Action? configureDelegate) + { + builder.Services.TryAddSingleton(svc => new EmbeddedFontLoader(svc.CreateLogger())); + builder.Services.TryAddSingleton(svc => new FontRegistrar(svc.GetRequiredService(), svc.CreateLogger())); + builder.Services.TryAddSingleton(svc => new FontManager(svc.GetRequiredService(), svc.CreateLogger())); + if (configureDelegate != null) + { + builder.Services.AddSingleton(new FontsRegistration(configureDelegate)); + } + builder.Services.AddSingleton(); + return builder; + } + + + internal class FontsRegistration + { + private readonly Action _registerFonts; + + public FontsRegistration(Action registerFonts) + { + _registerFonts = registerFonts; + } + + internal void AddFonts(IFontCollection fonts) + { + _registerFonts(fonts); + } + } + + internal class FontInitializer : IMauiInitializeService + { + private readonly IEnumerable _fontsRegistrations; + readonly IFontRegistrar _fontRegistrar; + + public FontInitializer(IEnumerable fontsRegistrations, IFontRegistrar fontRegistrar) + { + _fontsRegistrations = fontsRegistrations; + _fontRegistrar = fontRegistrar; + } + + public void Initialize(IServiceProvider __) + { + if (_fontsRegistrations != null) + { + var fontsBuilder = new FontCollection(); + + // Run all the user-defined registrations + foreach (var font in _fontsRegistrations) + { + font.AddFonts(fontsBuilder); + } + + // Register the fonts in the registrar + foreach (var font in fontsBuilder) + { + if (font.Assembly == null) + _fontRegistrar.Register(font.Filename, font.Alias); + else + _fontRegistrar.Register(font.Filename, font.Alias, font.Assembly); + } + } + } + } + } +} diff --git a/src/Core/src/Core/HandlerMauiAppBuilderExtensions.cs b/src/Core/src/Core/HandlerMauiAppBuilderExtensions.cs new file mode 100644 index 000000000000..f4cdba0e543e --- /dev/null +++ b/src/Core/src/Core/HandlerMauiAppBuilderExtensions.cs @@ -0,0 +1,36 @@ +using System; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Maui.Hosting; +using Microsoft.Maui.Hosting.Internal; + +namespace Microsoft.Maui +{ + public static class HandlerMauiAppBuilderExtensions + { + public static MauiAppBuilder ConfigureMauiHandlers(this MauiAppBuilder builder, Action? configureDelegate) + { + builder.Services.TryAddSingleton(); + if (configureDelegate != null) + { + builder.Services.AddSingleton(new HandlerRegistration(configureDelegate)); + } + return builder; + } + + internal class HandlerRegistration + { + private readonly Action _registerAction; + + public HandlerRegistration(Action registerAction) + { + _registerAction = registerAction; + } + + internal void AddRegistration(IMauiHandlersCollection builder) + { + _registerAction(builder); + } + } + } +} diff --git a/src/Core/src/Core/IStartup.cs b/src/Core/src/Core/IStartup.cs deleted file mode 100644 index 44048a803f13..000000000000 --- a/src/Core/src/Core/IStartup.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Microsoft.Maui.Hosting; - -namespace Microsoft.Maui -{ - /// - /// Startup allow to configure and instantiate application services. - /// - public interface IStartup - { - /// - /// Configures the application. - /// Configure are called by the .NET MAUI Core runtime when the app starts. - /// - /// Defines a class that provides the mechanisms to configure an application's dependencies. - void Configure(IAppHostBuilder appBuilder); - } - - /// - /// Allow to create a custom IAppHostBuilder instance. - /// - public interface IAppHostBuilderStartup : IStartup - { - /// - /// Create and configure a builder object. - /// - /// The new instance of the IAppHostBuilder. - IAppHostBuilder CreateAppHostBuilder(); - } -} \ No newline at end of file diff --git a/src/Core/src/Core/ImageSourcesMauiAppBuilderExtensions.cs b/src/Core/src/Core/ImageSourcesMauiAppBuilderExtensions.cs new file mode 100644 index 000000000000..af321e24dac4 --- /dev/null +++ b/src/Core/src/Core/ImageSourcesMauiAppBuilderExtensions.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Maui.Hosting; +using Microsoft.Maui.Hosting.Internal; + +namespace Microsoft.Maui +{ + public static class ImageSourcesMauiAppBuilderExtensions + { + public static MauiAppBuilder ConfigureImageSources(this MauiAppBuilder builder) + { + builder.ConfigureImageSources(services => + { + services.AddService(svcs => new FileImageSourceService(svcs.GetService(), svcs.CreateLogger())); + services.AddService(svcs => new FontImageSourceService(svcs.GetRequiredService(), svcs.CreateLogger())); + services.AddService(svcs => new StreamImageSourceService(svcs.CreateLogger())); + services.AddService(svcs => new UriImageSourceService(svcs.CreateLogger())); + }); + return builder; + } + + public static MauiAppBuilder ConfigureImageSources(this MauiAppBuilder builder, Action? configureDelegate) + { + if (configureDelegate != null) + { + builder.Services.AddSingleton(new ImageSourceRegistration(configureDelegate)); + } + + builder.Services.AddSingleton(); + builder.Services.AddSingleton(svcs => new ImageSourceServiceProvider(svcs.GetRequiredService(), svcs)); + builder.Services.AddSingleton(); + + return builder; + } + + class ImageSourceRegistration + { + private readonly Action _registerAction; + + public ImageSourceRegistration(Action registerAction) + { + _registerAction = registerAction; + } + + internal void AddRegistration(IImageSourceServiceCollection builder) + { + _registerAction(builder); + } + } + + class ImageSourceServiceBuilder : MauiServiceCollection, IImageSourceServiceCollection + { + public ImageSourceServiceBuilder(IEnumerable registrationActions) + { + if (registrationActions != null) + { + foreach (var effectRegistration in registrationActions) + { + effectRegistration.AddRegistration(this); + } + } + } + } + } +} diff --git a/src/Core/src/Core/MauiApp.cs b/src/Core/src/Core/MauiApp.cs new file mode 100644 index 000000000000..1d96113eb967 --- /dev/null +++ b/src/Core/src/Core/MauiApp.cs @@ -0,0 +1,87 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace Microsoft.Maui +{ + public sealed class MauiApp : IHost + { + private readonly IHost _host; + + internal MauiApp(IHost host) + { + _host = host; + Logger = host.Services.GetRequiredService().CreateLogger("TODO: Environment.ApplicationName"); + } + + /// + /// The application's configured services. + /// + public IServiceProvider Services => _host.Services; + + /// + /// The application's configured . + /// + public IConfiguration Configuration => _host.Services.GetRequiredService(); + + /// + /// Allows consumers to be notified of application lifetime events. + /// + public IHostApplicationLifetime Lifetime => _host.Services.GetRequiredService(); + + /// + /// The default logger for the application. + /// + public ILogger Logger { get; } + + /// + /// Initializes a new instance of the class with preconfigured defaults. + /// + /// The . + public static MauiApp Create() => new MauiAppBuilder().Build(); + + /// + /// Initializes a new instance of the class with preconfigured defaults. + /// + /// The . + public static MauiAppBuilder CreateBuilder() => new(); + + /// + /// Initializes a new instance of the class with optional defaults. + /// + /// Whether to create the with common defaults. + /// The . + public static MauiAppBuilder CreateBuilder(bool useDefaults = true) => new(useDefaults); + + /// + /// Start the application. + /// + /// + /// + /// A that represents the startup of the . + /// Successful completion indicates the HTTP server is ready to accept new requests. + /// + public Task StartAsync(CancellationToken cancellationToken = default) => + _host.StartAsync(cancellationToken); + + /// + /// Shuts down the application. + /// + /// + /// + /// A that represents the shutdown of the . + /// Successful completion indicates that all the HTTP server has stopped. + /// + public Task StopAsync(CancellationToken cancellationToken = default) => + _host.StopAsync(cancellationToken); + + /// + /// Disposes the application. + /// + void IDisposable.Dispose() => _host.Dispose(); + } +} diff --git a/src/Core/src/Core/MauiAppBuilder.cs b/src/Core/src/Core/MauiAppBuilder.cs new file mode 100644 index 000000000000..54a0e8ee6fcd --- /dev/null +++ b/src/Core/src/Core/MauiAppBuilder.cs @@ -0,0 +1,167 @@ +using System.Collections.Generic; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Maui.Hosting; +using Microsoft.Maui.LifecycleEvents; + +namespace Microsoft.Maui +{ + /// + /// A builder for .NET MAUI cross-platform applications and services. + /// + public sealed class MauiAppBuilder + { + private readonly HostBuilder _hostBuilder = new(); + private readonly BootstrapHostBuilder _bootstrapHostBuilder; + private readonly MauiApplicationServiceCollection _services = new(); + + private MauiApp? _builtApplication; + + internal MauiAppBuilder(bool useDefaults = true) + { + Services = _services; + + // Run methods to configure both generic and web host defaults early to populate config from appsettings.json + // environment variables (both DOTNET_ and ASPNETCORE_ prefixed) and other possible default sources to prepopulate + // the correct defaults. + _bootstrapHostBuilder = new BootstrapHostBuilder(Services, _hostBuilder.Properties); + + _bootstrapHostBuilder.ConfigureHostConfiguration(config => + { + // Disable reloading config on change so we don't use up system file watchers, which are a limited resource + // https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-5.0#disable-app-configuration-reload-on-change + config.AddInMemoryCollection(new Dictionary { { "hostBuilder:reloadConfigOnChange", "false" } }); + }); + + // Don't specify the args here since we want to apply them later so that args + // can override the defaults specified by ConfigureWebHostDefaults + _bootstrapHostBuilder.ConfigureDefaults(args: null); + + _bootstrapHostBuilder.ConfigureHostConfiguration(config => + { + // TODO: This has no more code left. Delete? + }); + + Configuration = new(); + + // This is the application configuration + var hostContext = _bootstrapHostBuilder.RunDefaultCallbacks(Configuration, _hostBuilder); + + Logging = new LoggingBuilder(Services); + Host = new ConfigureHostBuilder(hostContext, Configuration, Services); + + if (useDefaults) + { + // Register required services + this.ConfigureMauiHandlers(configureDelegate: null); + + this.ConfigureFonts(); + this.ConfigureImageSources(); + this.ConfigureAnimations(); + this.ConfigureCrossPlatformLifecycleEvents(); + } + } + + /// + /// A collection of services for the application to compose. This is useful for adding user provided or framework provided services. + /// + public IServiceCollection Services { get; } + + /// + /// A collection of configuration providers for the application to compose. This is useful for adding new configuration sources and providers. + /// + public ConfigurationManager Configuration { get; } + + /// + /// A collection of logging providers for the application to compose. This is useful for adding new logging providers. + /// + public ILoggingBuilder Logging { get; } + + /// + /// An for configuring host specific properties, but not building. + /// To build after configuration, call . + /// + public ConfigureHostBuilder Host { get; } + + /// + /// Builds the . + /// + /// A configured . + public MauiApp Build() + { + // Copy the configuration sources into the final IConfigurationBuilder + _hostBuilder.ConfigureHostConfiguration(builder => + { + foreach (var source in ((IConfigurationBuilder)Configuration).Sources) + { + builder.Sources.Add(source); + } + + foreach (var kvp in ((IConfigurationBuilder)Configuration).Properties) + { + builder.Properties[kvp.Key] = kvp.Value; + } + }); + + // This needs to go here to avoid adding the IHostedService that boots the server twice (the GenericWebHostService). + // Copy the services that were added via WebApplicationBuilder.Services into the final IServiceCollection + _hostBuilder.ConfigureServices((context, services) => + { + // We've only added services configured by the GenericWebHostBuilder and WebHost.ConfigureWebDefaults + // at this point. HostBuilder news up a new ServiceCollection in HostBuilder.Build() we haven't seen + // until now, so we cannot clear these services even though some are redundant because + // we called ConfigureWebHostDefaults on both the _deferredHostBuilder and _hostBuilder. + foreach (var s in _services) + { + services.Add(s); + } + + // Add any services to the user visible service collection so that they are observable + // just in case users capture the Services property. Orchard does this to get a "blueprint" + // of the service collection + + // Drop the reference to the existing collection and set the inner collection + // to the new one. This allows code that has references to the service collection to still function. + _services.InnerCollection = services; + }); + + // Run the other callbacks on the final host builder + Host.RunDeferredCallbacks(_hostBuilder); + + _builtApplication = new MauiApp(_hostBuilder.Build()); + + // Make builder.Configuration match the final configuration. To do that + // we clear the sources and add the built configuration as a source + ((IConfigurationBuilder)Configuration).Sources.Clear(); + Configuration.AddConfiguration(_builtApplication.Configuration); + + // Mark the service collection as read-only to prevent future modifications + _services.IsReadOnly = true; + + + var initServices = _builtApplication.Services.GetService>(); + if (initServices != null) + { + foreach (var instance in initServices) + { + instance.Initialize(_builtApplication.Services); + } + } + + + return _builtApplication; + } + + private class LoggingBuilder : ILoggingBuilder + { + public LoggingBuilder(IServiceCollection services) + { + Services = services; + } + + public IServiceCollection Services { get; } + } + } +} diff --git a/src/Core/src/Core/MauiApplicationServiceCollection.cs b/src/Core/src/Core/MauiApplicationServiceCollection.cs new file mode 100644 index 000000000000..36e1f5303754 --- /dev/null +++ b/src/Core/src/Core/MauiApplicationServiceCollection.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; + +namespace Microsoft.Maui +{ + internal sealed class MauiApplicationServiceCollection : IServiceCollection + { + private IServiceCollection _services = new ServiceCollection(); + + public ServiceDescriptor this[int index] + { + get => _services[index]; + set + { + CheckServicesAccess(); + _services[index] = value; + } + } + public int Count => _services.Count; + + public bool IsReadOnly { get; set; } + + public IServiceCollection InnerCollection + { + get => _services; + set + { + CheckServicesAccess(); + _services = value; + } + } + + public void Add(ServiceDescriptor item) + { + CheckServicesAccess(); + + _services.Add(item); + } + + public void Clear() + { + CheckServicesAccess(); + + _services.Clear(); + } + + public bool Contains(ServiceDescriptor item) + { + return _services.Contains(item); + } + + public void CopyTo(ServiceDescriptor[] array, int arrayIndex) + { + _services.CopyTo(array, arrayIndex); + } + + public IEnumerator GetEnumerator() + { + return _services.GetEnumerator(); + } + + public int IndexOf(ServiceDescriptor item) + { + return _services.IndexOf(item); + } + + public void Insert(int index, ServiceDescriptor item) + { + CheckServicesAccess(); + + _services.Insert(index, item); + } + + public bool Remove(ServiceDescriptor item) + { + CheckServicesAccess(); + + return _services.Remove(item); + } + + public void RemoveAt(int index) + { + CheckServicesAccess(); + + _services.RemoveAt(index); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + private void CheckServicesAccess() + { + if (IsReadOnly) + { + throw new InvalidOperationException("Cannot modify ServiceCollection after application is built."); + } + } + } +} diff --git a/src/Core/src/Hosting/Animations/AppHostBuilderExtensions.cs b/src/Core/src/Hosting/Animations/AppHostBuilderExtensions.cs index 64def495ebe3..c96f2c129bce 100644 --- a/src/Core/src/Hosting/Animations/AppHostBuilderExtensions.cs +++ b/src/Core/src/Hosting/Animations/AppHostBuilderExtensions.cs @@ -8,18 +8,15 @@ namespace Microsoft.Maui.Hosting { public static partial class AppHostBuilderExtensions { - public static IAppHostBuilder ConfigureAnimations(this IAppHostBuilder builder) + public static MauiAppBuilder ConfigureAnimations(this MauiAppBuilder builder) { - builder.ConfigureServices(services => - { #if __ANDROID__ - services.AddSingleton(svcs => new EnergySaverListenerManager()); - services.AddTransient(svcs => new NativeTicker(svcs.GetRequiredService())); + builder.Services.AddSingleton(svcs => new EnergySaverListenerManager()); + builder.Services.AddTransient(svcs => new NativeTicker(svcs.GetRequiredService())); #else - services.AddTransient(svcs => new NativeTicker()); + builder.Services.AddTransient(svcs => new NativeTicker()); #endif - services.AddTransient(svcs => new AnimationManager(svcs.GetRequiredService())); - }); + builder.Services.AddTransient(svcs => new AnimationManager(svcs.GetRequiredService())); return builder; } diff --git a/src/Core/src/Hosting/AppHost.cs b/src/Core/src/Hosting/AppHost.cs deleted file mode 100644 index 6dbd530e5b71..000000000000 --- a/src/Core/src/Hosting/AppHost.cs +++ /dev/null @@ -1,21 +0,0 @@ -#nullable enable -using Microsoft.Maui.LifecycleEvents; - -namespace Microsoft.Maui.Hosting -{ - public static class AppHost - { - public static IAppHostBuilder CreateDefaultBuilder() - { - var builder = new AppHostBuilder(); - - builder.UseMicrosoftExtensionsServiceProviderFactory(); - builder.ConfigureFonts(); - builder.ConfigureImageSources(); - builder.ConfigureAnimations(); - builder.ConfigureCrossPlatformLifecycleEvents(); - - return builder; - } - } -} \ No newline at end of file diff --git a/src/Core/src/Hosting/AppHostBuilder.cs b/src/Core/src/Hosting/AppHostBuilder.cs deleted file mode 100644 index d69537ad6280..000000000000 --- a/src/Core/src/Hosting/AppHostBuilder.cs +++ /dev/null @@ -1,280 +0,0 @@ -#nullable enable -using System; -using System.Collections.Generic; -using System.Reflection; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.Maui.Hosting.Internal; - -namespace Microsoft.Maui.Hosting -{ - public class AppHostBuilder : IAppHostBuilder - { - readonly Dictionary>> _configureServiceBuilderActions = new Dictionary>>(); - readonly List _configureServiceBuilderInstances = new List(); - readonly List> _configureHostConfigActions = new List>(); - readonly List> _configureAppConfigActions = new List>(); - readonly List> _configureServicesActions = new List>(); - readonly List _configureContainerActions = new List(); - readonly Func _serviceCollectionFactory = new Func(() => new MauiServiceCollection()); - - IServiceFactoryAdapter _serviceProviderFactory = new ServiceFactoryAdapter(new MauiServiceProviderFactory(false)); - - bool _hostBuilt; - HostBuilderContext? _hostBuilderContext; - IHostEnvironment? _hostEnvironment; - IServiceProvider? _serviceProvider; - IServiceCollection? _services; - IConfiguration? _hostConfiguration; - IConfiguration? _appConfiguration; - - public AppHostBuilder() - { - // This is here just to make sure that the IMauiHandlersServiceProvider gets registered. - this.ConfigureMauiHandlers(handlers => { }); - } - - public IDictionary Properties => new Dictionary(); - - public IAppHost Build() - { - if (_hostBuilt) - throw new InvalidOperationException("Build can only be called once."); - - _hostBuilt = true; - - // the order is important here - BuildHostConfiguration(); - CreateHostingEnvironment(); - CreateHostBuilderContext(); - BuildAppConfiguration(); - - _services = _serviceCollectionFactory(); - if (_services == null) - throw new InvalidOperationException("The ServiceCollection cannot be null"); - - BuildServiceCollections(_services); - BuildServices(_services); - - _services.TryAddSingleton(); - - _serviceProvider = ConfigureContainerAndGetProvider(_services); - if (_serviceProvider == null) - throw new InvalidOperationException($"The IServiceProviderFactory returned a null IServiceProvider."); - - ConfigureServiceCollectionBuilders(_serviceProvider); - - return new Internal.AppHost(_serviceProvider, null); - } - - public IAppHostBuilder ConfigureAppConfiguration(Action configureDelegate) - { - _configureAppConfigActions.Add(configureDelegate ?? throw new ArgumentNullException(nameof(configureDelegate))); - return this; - } - - public IAppHostBuilder ConfigureContainer(Action configureDelegate) - { - _configureContainerActions.Add(new ConfigureContainerAdapter(configureDelegate ?? throw new ArgumentNullException(nameof(configureDelegate)))); - return this; - } - - public IAppHostBuilder ConfigureHostConfiguration(Action configureDelegate) - { - _configureHostConfigActions.Add(configureDelegate ?? throw new ArgumentNullException(nameof(configureDelegate))); - return this; - } - - public IAppHostBuilder ConfigureServices(Action configureDelegate) - { - _configureServicesActions.Add(configureDelegate ?? throw new ArgumentNullException(nameof(configureDelegate))); - return this; - } - - public IAppHostBuilder ConfigureServices(Action configureDelegate) - where TBuilder : IMauiServiceBuilder, new() - { - _ = configureDelegate ?? throw new ArgumentNullException(nameof(configureDelegate)); - - var key = typeof(TBuilder); - if (!_configureServiceBuilderActions.TryGetValue(key, out var list)) - { - list = new List>(); - _configureServiceBuilderActions.Add(key, list); - } - - list.Add((context, builder) => configureDelegate(context, (TBuilder)builder)); - - return this; - } - -#pragma warning disable CS8714 // The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'notnull' constraint. - public IAppHostBuilder UseServiceProviderFactory(IServiceProviderFactory factory) - { - _serviceProviderFactory = new ServiceFactoryAdapter(factory ?? throw new ArgumentNullException(nameof(factory))); - return this; - } - - public IAppHostBuilder UseServiceProviderFactory(Func> factory) - { - _serviceProviderFactory = new ServiceFactoryAdapter(() => _hostBuilderContext!, factory ?? throw new ArgumentNullException(nameof(factory))); - - return this; - } -#pragma warning restore CS8714 // The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'notnull' constraint - - void BuildHostConfiguration() - { - var configBuilder = new ConfigurationBuilder(); - foreach (var buildAction in _configureHostConfigActions) - { - buildAction(configBuilder); - } - _hostConfiguration = configBuilder.Build(); - } - - void CreateHostingEnvironment() - { - _hostEnvironment = new AppHostEnvironment() - { - //ApplicationName = _hostConfiguration[HostDefaults.ApplicationKey], - //EnvironmentName = _hostConfiguration[HostDefaults.EnvironmentKey] ?? Environments.Production, - //ContentRootPath = ResolveContentRootPath(_hostConfiguration[HostDefaults.ContentRootKey], AppContext.BaseDirectory), - }; - - if (string.IsNullOrEmpty(_hostEnvironment.ApplicationName)) - { - // Note GetEntryAssembly returns null for the net4x console test runner. - _hostEnvironment.ApplicationName = Assembly.GetEntryAssembly()?.GetName().Name; - } - } - - void CreateHostBuilderContext() - { - _hostBuilderContext = new HostBuilderContext(Properties) - { - HostingEnvironment = _hostEnvironment, - }; - } - - void BuildServices(IServiceCollection services) - { - if (services == null) - throw new ArgumentNullException(nameof(services)); - if (_hostBuilderContext == null) - throw new InvalidOperationException($"The HostBuilderContext was not set."); - - if (_appConfiguration != null) - services.AddSingleton(_appConfiguration); - - foreach (Action configureServicesAction in _configureServicesActions) - { - configureServicesAction(_hostBuilderContext, services); - } - } - - void BuildAppConfiguration() - { - if (_hostBuilderContext == null) - throw new InvalidOperationException($"The HostBuilderContext was not set."); - - var configBuilder = new ConfigurationBuilder(); - configBuilder.AddConfiguration(_hostConfiguration); - foreach (var buildAction in _configureAppConfigActions) - { - buildAction(_hostBuilderContext, configBuilder); - } - _appConfiguration = configBuilder.Build(); - - _hostBuilderContext.Configuration = _appConfiguration; - } - - IServiceProvider ConfigureContainerAndGetProvider(IServiceCollection services) - { - if (_hostBuilderContext == null) - throw new InvalidOperationException($"The HostBuilderContext was not set."); - - object containerBuilder = _serviceProviderFactory.CreateBuilder(services); - - foreach (IConfigureContainerAdapter containerAction in _configureContainerActions) - { - containerAction.ConfigureContainer(_hostBuilderContext, containerBuilder); - } - - return _serviceProviderFactory.CreateServiceProvider(containerBuilder); - } - - void BuildServiceCollections(IServiceCollection? services) - { - if (services == null) - throw new ArgumentNullException(nameof(services)); - if (_hostBuilderContext == null) - throw new InvalidOperationException($"The HostBuilderContext was not set."); - - foreach (var pair in _configureServiceBuilderActions) - { - var instance = (IMauiServiceBuilder)Activator.CreateInstance(pair.Key)!; - - foreach (var action in pair.Value) - { - action(_hostBuilderContext, instance); - } - - instance.ConfigureServices(_hostBuilderContext, services); - - _configureServiceBuilderInstances.Add(instance); - } - } - - void ConfigureServiceCollectionBuilders(IServiceProvider? serviceProvider) - { - if (serviceProvider == null) - throw new ArgumentNullException(nameof(serviceProvider)); - if (_hostBuilderContext == null) - throw new InvalidOperationException($"The HostBuilderContext was not set."); - - foreach (var instance in _configureServiceBuilderInstances) - { - instance.Configure(_hostBuilderContext, serviceProvider); - } - } - - IHostBuilder IHostBuilder.ConfigureHostConfiguration(Action configureDelegate) - { - return ConfigureHostConfiguration(configureDelegate); - } - - IHostBuilder IHostBuilder.ConfigureAppConfiguration(Action configureDelegate) - { - return ConfigureAppConfiguration(configureDelegate); - } - - IHostBuilder IHostBuilder.ConfigureServices(Action configureDelegate) - { - return ConfigureServices(configureDelegate); - } - - IHostBuilder IHostBuilder.UseServiceProviderFactory(IServiceProviderFactory factory) - { - return UseServiceProviderFactory(factory); - } - - IHostBuilder IHostBuilder.UseServiceProviderFactory(Func> factory) - { - return UseServiceProviderFactory(factory); - } - - IHostBuilder IHostBuilder.ConfigureContainer(Action configureDelegate) - { - return ConfigureContainer(configureDelegate); - } - - IHost IHostBuilder.Build() - { - return Build(); - } - } -} \ No newline at end of file diff --git a/src/Core/src/Hosting/AppHostBuilderExtensions.cs b/src/Core/src/Hosting/AppHostBuilderExtensions.cs deleted file mode 100644 index 4269fe29bc03..000000000000 --- a/src/Core/src/Hosting/AppHostBuilderExtensions.cs +++ /dev/null @@ -1,90 +0,0 @@ -#nullable enable -using System; -using System.Collections.Generic; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.Hosting; -using Microsoft.Maui.Graphics; -using Microsoft.Maui.Handlers; -using Microsoft.Maui.Hosting.Internal; - -namespace Microsoft.Maui.Hosting -{ - public static partial class AppHostBuilderExtensions - { - public static IAppHostBuilder ConfigureMauiHandlers(this IAppHostBuilder builder, Action configureDelegate) - { - builder.ConfigureServices((_, handlers) => configureDelegate(handlers)); - return builder; - } - - public static IAppHostBuilder ConfigureMauiHandlers(this IAppHostBuilder builder, Action configureDelegate) - { - builder.ConfigureServices(configureDelegate); - return builder; - } - - public static IAppHostBuilder ConfigureServices(this IAppHostBuilder builder, Action configureDelegate) - { - builder.ConfigureServices((_, services) => configureDelegate(services)); - return builder; - } - - public static IAppHostBuilder ConfigureServices(this IAppHostBuilder builder, Action configureDelegate) - where TBuilder : IMauiServiceBuilder, new() - { - builder.ConfigureServices((_, services) => configureDelegate(services)); - return builder; - } - - public static IAppHostBuilder ConfigureServices(this IAppHostBuilder builder) - where TBuilder : IMauiServiceBuilder, new() - { - builder.ConfigureServices((_, services) => { }); - return builder; - } - - public static IAppHostBuilder ConfigureAppConfiguration(this IAppHostBuilder builder, Action configureDelegate) - { - builder.ConfigureAppConfiguration((_, config) => configureDelegate(config)); - return builder; - } - - public static IAppHostBuilder UseMauiServiceProviderFactory(this IAppHostBuilder builder, bool constructorInjection) - { - builder.UseServiceProviderFactory(new MauiServiceProviderFactory(constructorInjection)); - return builder; - } - - public static IAppHostBuilder UseMicrosoftExtensionsServiceProviderFactory(this IAppHostBuilder builder) - { - builder.UseServiceProviderFactory(new DIExtensionsServiceProviderFactory()); - return builder; - } - - // To use the Microsoft.Extensions.DependencyInjection ServiceCollection and not the MAUI one - class DIExtensionsServiceProviderFactory : IServiceProviderFactory - { - public ServiceCollection CreateBuilder(IServiceCollection services) - => new ServiceCollection { services }; - - public IServiceProvider CreateServiceProvider(ServiceCollection containerBuilder) - => containerBuilder.BuildServiceProvider(); - } - - class HandlerCollectionBuilder : MauiHandlersCollection, IMauiServiceBuilder - { - public void ConfigureServices(HostBuilderContext context, IServiceCollection services) - { - var provider = new MauiHandlersServiceProvider(this); - - services.AddSingleton(provider); - } - - public void Configure(HostBuilderContext context, IServiceProvider services) - { - } - } - } -} diff --git a/src/Core/src/Hosting/Fonts/AppHostBuilderExtensions.cs b/src/Core/src/Hosting/Fonts/AppHostBuilderExtensions.cs deleted file mode 100644 index 3501ad60ce6e..000000000000 --- a/src/Core/src/Hosting/Fonts/AppHostBuilderExtensions.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Maui.Hosting.Internal; - -namespace Microsoft.Maui.Hosting -{ - public static partial class AppHostBuilderExtensions - { - public static IAppHostBuilder ConfigureFonts(this IAppHostBuilder builder) - { - builder.ConfigureServices((a, b) => { }); - return builder; - } - - public static IAppHostBuilder ConfigureFonts(this IAppHostBuilder builder, Action configureDelegate) - { - builder.ConfigureServices((_, fonts) => configureDelegate(fonts)); - return builder; - } - - public static IAppHostBuilder ConfigureFonts(this IAppHostBuilder builder, Action configureDelegate) - { - builder.ConfigureServices(configureDelegate); - return builder; - } - - class FontCollectionBuilder : FontCollection, IMauiServiceBuilder - { - public void ConfigureServices(HostBuilderContext context, IServiceCollection services) - { - services.AddSingleton(svc => new EmbeddedFontLoader(svc.CreateLogger())); - services.AddSingleton(svc => new FontRegistrar(svc.GetRequiredService(), svc.CreateLogger())); - services.AddSingleton(svc => new FontManager(svc.GetRequiredService(), svc.CreateLogger())); - } - - public void Configure(HostBuilderContext context, IServiceProvider services) - { - var fontRegistrar = services.GetService(); - if (fontRegistrar == null) - return; - - foreach (var font in this) - { - if (font.Assembly == null) - fontRegistrar.Register(font.Filename, font.Alias); - else - fontRegistrar.Register(font.Filename, font.Alias, font.Assembly); - } - } - } - } -} \ No newline at end of file diff --git a/src/Core/src/Hosting/IAppHost.cs b/src/Core/src/Hosting/IAppHost.cs deleted file mode 100644 index ae0ca8e314f6..000000000000 --- a/src/Core/src/Hosting/IAppHost.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Microsoft.Extensions.Hosting; - -namespace Microsoft.Maui.Hosting -{ - public interface IAppHost : IHost - { - IMauiHandlersServiceProvider Handlers { get; } - } -} \ No newline at end of file diff --git a/src/Core/src/Hosting/IAppHostBuilder.cs b/src/Core/src/Hosting/IAppHostBuilder.cs deleted file mode 100644 index b2ffa4e82d86..000000000000 --- a/src/Core/src/Hosting/IAppHostBuilder.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; - -namespace Microsoft.Maui.Hosting -{ - public interface IAppHostBuilder : IHostBuilder - { - IAppHostBuilder ConfigureServices(Action configureDelegate) where TBuilder : IMauiServiceBuilder, new(); - new IAppHostBuilder ConfigureAppConfiguration(Action configureDelegate); - new IAppHostBuilder ConfigureContainer(Action configureDelegate); - new IAppHostBuilder ConfigureHostConfiguration(Action configureDelegate); - new IAppHostBuilder ConfigureServices(Action configureDelegate); -#pragma warning disable CS8714 // The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'notnull' constraint. - new IAppHostBuilder UseServiceProviderFactory(IServiceProviderFactory factory); - new IAppHostBuilder UseServiceProviderFactory(Func> factory); -#pragma warning restore CS8714 // The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'notnull' constraint. - new IAppHost Build(); - } -} \ No newline at end of file diff --git a/src/Core/src/Hosting/IMauiInitializeService.cs b/src/Core/src/Hosting/IMauiInitializeService.cs new file mode 100644 index 000000000000..daecec20ad10 --- /dev/null +++ b/src/Core/src/Hosting/IMauiInitializeService.cs @@ -0,0 +1,10 @@ +using System; +using Microsoft.Extensions.Hosting; + +namespace Microsoft.Maui.Hosting +{ + public interface IMauiInitializeService + { + void Initialize(IServiceProvider services); + } +} \ No newline at end of file diff --git a/src/Core/src/Hosting/IMauiServiceBuilder.cs b/src/Core/src/Hosting/IMauiServiceBuilder.cs deleted file mode 100644 index d37c91aab4c5..000000000000 --- a/src/Core/src/Hosting/IMauiServiceBuilder.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; - -namespace Microsoft.Maui.Hosting -{ - public interface IMauiServiceBuilder - { - void ConfigureServices(HostBuilderContext context, IServiceCollection services); - - void Configure(HostBuilderContext context, IServiceProvider services); - } -} \ No newline at end of file diff --git a/src/Core/src/Hosting/ImageSources/AppHostBuilderExtensions.cs b/src/Core/src/Hosting/ImageSources/AppHostBuilderExtensions.cs deleted file mode 100644 index c4ce5f6a854c..000000000000 --- a/src/Core/src/Hosting/ImageSources/AppHostBuilderExtensions.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Maui.Hosting.Internal; - -namespace Microsoft.Maui.Hosting -{ - public static partial class AppHostBuilderExtensions - { - public static IAppHostBuilder ConfigureImageSources(this IAppHostBuilder builder) - { - builder.ConfigureImageSources(services => - { - services.AddService(svcs => new FileImageSourceService(svcs.GetService(), svcs.CreateLogger())); - services.AddService(svcs => new FontImageSourceService(svcs.GetRequiredService(), svcs.CreateLogger())); - services.AddService(svcs => new StreamImageSourceService(svcs.CreateLogger())); - services.AddService(svcs => new UriImageSourceService(svcs.CreateLogger())); - }); - return builder; - } - - public static IAppHostBuilder ConfigureImageSources(this IAppHostBuilder builder, Action configureDelegate) - { - builder.ConfigureServices((_, services) => configureDelegate(services)); - return builder; - } - - public static IAppHostBuilder ConfigureImageSources(this IAppHostBuilder builder, Action configureDelegate) - { - builder.ConfigureServices(configureDelegate); - return builder; - } - - class ImageSourceServiceBuilder : MauiServiceCollection, IImageSourceServiceCollection, IMauiServiceBuilder - { - public void ConfigureServices(HostBuilderContext context, IServiceCollection services) - { - services.AddSingleton(); - services.AddSingleton(svcs => new ImageSourceServiceProvider(this, svcs)); - } - - public void Configure(HostBuilderContext context, IServiceProvider services) - { - } - } - } -} \ No newline at end of file diff --git a/src/Core/src/Hosting/ImageSources/IImageSourceServiceCollection.cs b/src/Core/src/Hosting/ImageSources/IImageSourceServiceCollection.cs index d1d62e3ebd73..5154f0f98b02 100644 --- a/src/Core/src/Hosting/ImageSources/IImageSourceServiceCollection.cs +++ b/src/Core/src/Hosting/ImageSources/IImageSourceServiceCollection.cs @@ -2,7 +2,7 @@ namespace Microsoft.Maui.Hosting { - public interface IImageSourceServiceCollection : IServiceCollection + public interface IImageSourceServiceCollection : IMauiServiceCollection { } } \ No newline at end of file diff --git a/src/Core/src/Hosting/ImageSources/ImageSourceServiceProvider.cs b/src/Core/src/Hosting/ImageSources/ImageSourceServiceProvider.cs index f872fee3f479..8b5c2bf7c0db 100644 --- a/src/Core/src/Hosting/ImageSources/ImageSourceServiceProvider.cs +++ b/src/Core/src/Hosting/ImageSources/ImageSourceServiceProvider.cs @@ -14,7 +14,7 @@ class ImageSourceServiceProvider : MauiServiceProvider, IImageSourceServiceProvi readonly ConcurrentDictionary _imageSourceCache = new ConcurrentDictionary(); readonly ConcurrentDictionary _serviceCache = new ConcurrentDictionary(); - public ImageSourceServiceProvider(IMauiServiceCollection collection, IServiceProvider hostServiceProvider) + public ImageSourceServiceProvider(IImageSourceServiceCollection collection, IServiceProvider hostServiceProvider) : base(collection, false) { HostServiceProvider = hostServiceProvider; diff --git a/src/Core/src/Hosting/Internal/AppHost.cs b/src/Core/src/Hosting/Internal/AppHost.cs deleted file mode 100644 index 48cdfd352741..000000000000 --- a/src/Core/src/Hosting/Internal/AppHost.cs +++ /dev/null @@ -1,59 +0,0 @@ -#nullable enable -using System; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; - -namespace Microsoft.Maui.Hosting.Internal -{ - class AppHost : IAppHost, IAsyncDisposable - { - readonly ILogger? _logger; - - public AppHost(IServiceProvider services, ILogger? logger) - { - Services = services ?? throw new ArgumentNullException(nameof(services)); - Handlers = Services.GetRequiredService(); - - _logger = logger; - } - - public IServiceProvider Services { get; } - - public IMauiHandlersServiceProvider Handlers { get; } - - public async Task StartAsync(CancellationToken cancellationToken = default) - { - _logger?.Starting(); - - await Task.Run(() => { }); - - _logger?.Started(); - } - - public async Task StopAsync(CancellationToken cancellationToken = default) - { - _logger?.Stopping(); - - _ = await Task.FromResult(new object()); - - _logger?.Stopped(); - } - - public void Dispose() => DisposeAsync().AsTask().GetAwaiter().GetResult(); - - public async ValueTask DisposeAsync() - { - switch (Services) - { - case IAsyncDisposable asyncDisposable: - await asyncDisposable.DisposeAsync().ConfigureAwait(false); - break; - case IDisposable disposable: - disposable.Dispose(); - break; - } - } - } -} \ No newline at end of file diff --git a/src/Core/src/Hosting/Internal/AppHostEnvironment.cs b/src/Core/src/Hosting/Internal/AppHostEnvironment.cs deleted file mode 100644 index a25dd97558f6..000000000000 --- a/src/Core/src/Hosting/Internal/AppHostEnvironment.cs +++ /dev/null @@ -1,18 +0,0 @@ -#nullable enable -using Microsoft.Extensions.FileProviders; -using Microsoft.Extensions.Hosting; - -namespace Microsoft.Maui.Hosting.Internal -{ - class AppHostEnvironment : IHostEnvironment - { - public AppHostEnvironment() - { - } - - public string? EnvironmentName { get; set; } - public string? ApplicationName { get; set; } - public string? ContentRootPath { get; set; } - public IFileProvider? ContentRootFileProvider { get; set; } - } -} \ No newline at end of file diff --git a/src/Core/src/Hosting/Internal/MauiHandlersServiceProvider.cs b/src/Core/src/Hosting/Internal/MauiHandlersServiceProvider.cs index ef9e01c41ff3..17dabc99837c 100644 --- a/src/Core/src/Hosting/Internal/MauiHandlersServiceProvider.cs +++ b/src/Core/src/Hosting/Internal/MauiHandlersServiceProvider.cs @@ -1,16 +1,27 @@ #nullable enable using System; +using System.Collections.Generic; namespace Microsoft.Maui.Hosting.Internal { class MauiHandlersServiceProvider : MauiServiceProvider, IMauiHandlersServiceProvider { - readonly IMauiHandlersCollection _collection; + public MauiHandlersServiceProvider(IEnumerable registrationActions) : + base(CreateHandlerCollection(registrationActions), constructorInjection: false) + { + } - public MauiHandlersServiceProvider(IMauiHandlersCollection collection) - : base(collection, false) + private static IMauiServiceCollection CreateHandlerCollection(IEnumerable registrationActions) { - _collection = collection; + var collection = new MauiHandlersCollection(); + if (registrationActions != null) + { + foreach (var registrationAction in registrationActions) + { + registrationAction.AddRegistration(collection); + } + } + return collection; } public IElementHandler? GetHandler(Type type) @@ -28,6 +39,6 @@ public MauiHandlersServiceProvider(IMauiHandlersCollection collection) return null; } - public IMauiHandlersCollection GetCollection() => _collection; + public IMauiHandlersCollection GetCollection() => (IMauiHandlersCollection)InternalCollection; } } \ No newline at end of file diff --git a/src/Core/src/Hosting/Internal/MauiServiceProvider.cs b/src/Core/src/Hosting/Internal/MauiServiceProvider.cs index da04ad2979f6..4490bf7b5aa0 100644 --- a/src/Core/src/Hosting/Internal/MauiServiceProvider.cs +++ b/src/Core/src/Hosting/Internal/MauiServiceProvider.cs @@ -17,6 +17,8 @@ class MauiServiceProvider : IMauiServiceProvider readonly IMauiServiceCollection _collection; readonly bool _constructorInjection; + protected IMauiServiceCollection InternalCollection => _collection; + // TODO: do this properly and support scopes readonly IDictionary _singletons; diff --git a/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.Android.cs b/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.Android.cs index ba2aa30f19b4..5f2da9c33f6e 100644 --- a/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.Android.cs +++ b/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.Android.cs @@ -6,7 +6,7 @@ namespace Microsoft.Maui.LifecycleEvents { public static partial class AppHostBuilderExtensions { - internal static IAppHostBuilder ConfigureCrossPlatformLifecycleEvents(this IAppHostBuilder builder) => + internal static MauiAppBuilder ConfigureCrossPlatformLifecycleEvents(this MauiAppBuilder builder) => builder.ConfigureLifecycleEvents(events => events.AddAndroid(OnConfigureLifeCycle)); static void OnConfigureLifeCycle(IAndroidLifecycleBuilder android) diff --git a/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.Standard.cs b/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.Standard.cs index cd880a07c910..ae21e1cae5ee 100644 --- a/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.Standard.cs +++ b/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.Standard.cs @@ -6,7 +6,7 @@ namespace Microsoft.Maui.LifecycleEvents { public static partial class AppHostBuilderExtensions { - internal static IAppHostBuilder ConfigureCrossPlatformLifecycleEvents(this IAppHostBuilder builder) => + internal static MauiAppBuilder ConfigureCrossPlatformLifecycleEvents(this MauiAppBuilder builder) => builder; } } diff --git a/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.Windows.cs b/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.Windows.cs index 030f1ecd20de..56a51980422e 100644 --- a/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.Windows.cs +++ b/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.Windows.cs @@ -6,7 +6,7 @@ namespace Microsoft.Maui.LifecycleEvents { public static partial class AppHostBuilderExtensions { - internal static IAppHostBuilder ConfigureCrossPlatformLifecycleEvents(this IAppHostBuilder builder) => + internal static MauiAppBuilder ConfigureCrossPlatformLifecycleEvents(this MauiAppBuilder builder) => builder.ConfigureLifecycleEvents(events => events.AddWindows(OnConfigureLifeCycle)); static void OnConfigureLifeCycle(IWindowsLifecycleBuilder windows) diff --git a/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.cs b/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.cs index 3370e0b0496a..9fd22b800716 100644 --- a/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.cs +++ b/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.cs @@ -1,36 +1,34 @@ using System; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Maui.Hosting; namespace Microsoft.Maui.LifecycleEvents { - public static partial class AppHostBuilderExtensions + public class LifecycleEventRegistration { - public static IAppHostBuilder ConfigureLifecycleEvents(this IAppHostBuilder builder, Action configureDelegate) - { - builder.ConfigureServices((_, lifecycle) => configureDelegate(lifecycle)); + private readonly Action _registerAction; - return builder; + public LifecycleEventRegistration(Action registerAction) + { + _registerAction = registerAction; } - public static IAppHostBuilder ConfigureLifecycleEvents(this IAppHostBuilder builder, Action configureDelegate) + internal void AddRegistration(ILifecycleBuilder effects) { - builder.ConfigureServices(configureDelegate); - - return builder; + _registerAction(effects); } + } - class LifecycleBuilder : LifecycleEventService, ILifecycleBuilder, IMauiServiceBuilder + public static partial class MauiAppHostBuilderExtensions + { + public static MauiAppBuilder ConfigureLifecycleEvents(this MauiAppBuilder builder, Action? configureDelegate) { - public void ConfigureServices(HostBuilderContext context, IServiceCollection services) + builder.Services.AddSingleton(); + if (configureDelegate != null) { - services.AddSingleton(this); + builder.Services.AddSingleton(new LifecycleEventRegistration(configureDelegate)); } - public void Configure(HostBuilderContext context, IServiceProvider services) - { - } + return builder; } } } \ No newline at end of file diff --git a/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.iOS.cs b/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.iOS.cs index 4ee68411fe1c..f8ee914c8ccf 100644 --- a/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.iOS.cs +++ b/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.iOS.cs @@ -6,7 +6,7 @@ namespace Microsoft.Maui.LifecycleEvents { public static partial class AppHostBuilderExtensions { - internal static IAppHostBuilder ConfigureCrossPlatformLifecycleEvents(this IAppHostBuilder builder) => + internal static MauiAppBuilder ConfigureCrossPlatformLifecycleEvents(this MauiAppBuilder builder) => builder.ConfigureLifecycleEvents(events => events.AddiOS(OnConfigureLifeCycle)); static void OnConfigureLifeCycle(IiOSLifecycleBuilder iOS) diff --git a/src/Core/src/Hosting/StartupExtensions.cs b/src/Core/src/Hosting/StartupExtensions.cs deleted file mode 100644 index d4b70a669bca..000000000000 --- a/src/Core/src/Hosting/StartupExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Microsoft.Maui.Hosting -{ - public static class StartupExtensions - { - public static IAppHostBuilder CreateAppHostBuilder(this IStartup startup) - { - if (startup is IAppHostBuilderStartup hostBuilderStartup) - return hostBuilderStartup.CreateAppHostBuilder(); - - return AppHost.CreateDefaultBuilder(); - } - - public static IAppHostBuilder ConfigureUsing(this IAppHostBuilder appHostBuilder, IStartup startup) - { - startup.Configure(appHostBuilder); - - return appHostBuilder; - } - } -} \ No newline at end of file diff --git a/src/Core/src/HotReload/AppHostBuilderExtensions.cs b/src/Core/src/HotReload/AppHostBuilderExtensions.cs index 7c1d786964ff..745f0b5ceaa1 100644 --- a/src/Core/src/HotReload/AppHostBuilderExtensions.cs +++ b/src/Core/src/HotReload/AppHostBuilderExtensions.cs @@ -9,27 +9,23 @@ namespace Microsoft.Maui.Hosting { public static partial class AppHostBuilderExtensions { - public static IAppHostBuilder EnableHotReload(this IAppHostBuilder builder, string? ideIp = null, int idePort = 9988) + public static MauiAppBuilder EnableHotReload(this MauiAppBuilder builder, string? ideIp = null, int idePort = 9988) { - builder.ConfigureServices(hotReload => + builder.Services.AddSingleton(new HotReloadBuilder { - hotReload.IdeIp = ideIp; - hotReload.IdePort = idePort; + IdeIp = ideIp, + IdePort = idePort, }); return builder; } - class HotReloadBuilder : IMauiServiceBuilder + class HotReloadBuilder : IMauiInitializeService { public string? IdeIp { get; set; } public int IdePort { get; set; } = 9988; - public void ConfigureServices(HostBuilderContext context, IServiceCollection services) - { - } - - public async void Configure(HostBuilderContext context, IServiceProvider services) + public async void Initialize(IServiceProvider services) { var handlers = services.GetRequiredService(); diff --git a/src/Core/src/LifecycleEvents/LifecycleEventService.cs b/src/Core/src/LifecycleEvents/LifecycleEventService.cs index 9b5ba9560a42..40c2d0d07879 100644 --- a/src/Core/src/LifecycleEvents/LifecycleEventService.cs +++ b/src/Core/src/LifecycleEvents/LifecycleEventService.cs @@ -4,10 +4,21 @@ namespace Microsoft.Maui.LifecycleEvents { - public class LifecycleEventService : ILifecycleEventService + public class LifecycleEventService : ILifecycleEventService, ILifecycleBuilder { readonly Dictionary> _mapper = new Dictionary>(); + public LifecycleEventService(IEnumerable registrations) + { + if (registrations != null) + { + foreach (var registrationAction in registrations) + { + registrationAction.AddRegistration(this); + } + } + } + public void AddEvent(string eventName, TDelegate action) where TDelegate : Delegate { diff --git a/src/Core/src/Platform/Android/MauiApplication.cs b/src/Core/src/Platform/Android/MauiApplication.cs index c86bed7fd08a..1b184c9b949f 100644 --- a/src/Core/src/Platform/Android/MauiApplication.cs +++ b/src/Core/src/Platform/Android/MauiApplication.cs @@ -11,16 +11,6 @@ namespace Microsoft.Maui { - public class MauiApplication : MauiApplication - where TStartup : IStartup, new() - { - public MauiApplication(IntPtr handle, JniHandleOwnership ownership) : base(handle, ownership) - { - } - - protected override IStartup OnCreateStartup() => new TStartup(); - } - public abstract class MauiApplication : Application { protected MauiApplication(IntPtr handle, JniHandleOwnership ownership) : base(handle, ownership) @@ -28,21 +18,25 @@ protected MauiApplication(IntPtr handle, JniHandleOwnership ownership) : base(ha Current = this; } - protected abstract IStartup OnCreateStartup(); + protected abstract MauiAppBuilder CreateAppBuilder(); public override void OnCreate() { RegisterActivityLifecycleCallbacks(new ActivityLifecycleCallbacks()); - var startup = OnCreateStartup(); + var builder = CreateAppBuilder(); + + //var startup = OnCreateStartup(); + + //var host = startup + // .CreateAppHostBuilder() + // .ConfigureServices(ConfigureNativeServices) + // .ConfigureUsing(startup) + // .Build(); - var host = startup - .CreateAppHostBuilder() - .ConfigureServices(ConfigureNativeServices) - .ConfigureUsing(startup) - .Build(); + var mauiApp = builder.Build(); - Services = host.Services; + Services = mauiApp.Services; Current.Services?.InvokeLifecycleEvents(del => del(this)); diff --git a/src/Core/src/Platform/Windows/MauiWinUIApplication.cs b/src/Core/src/Platform/Windows/MauiWinUIApplication.cs index 0bcdf5484b0a..124479b4d4ce 100644 --- a/src/Core/src/Platform/Windows/MauiWinUIApplication.cs +++ b/src/Core/src/Platform/Windows/MauiWinUIApplication.cs @@ -6,30 +6,27 @@ namespace Microsoft.Maui { - public class MauiWinUIApplication : MauiWinUIApplication - where TStartup : IStartup, new() - { - protected override IStartup OnCreateStartup() => new TStartup(); - } - public abstract class MauiWinUIApplication : UI.Xaml.Application { - protected abstract IStartup OnCreateStartup(); + protected abstract MauiAppBuilder CreateAppBuilder(); protected override void OnLaunched(UI.Xaml.LaunchActivatedEventArgs args) { LaunchActivatedEventArgs = args; - var startup = OnCreateStartup() ?? - throw new InvalidOperationException($"A valid startup object must be provided by overriding {nameof(OnCreateStartup)}."); + var builder = CreateAppBuilder(); + var mauiApp = builder.Build(); + + //var startup = OnCreateStartup() ?? + // throw new InvalidOperationException($"A valid startup object must be provided by overriding {nameof(OnCreateStartup)}."); - var host = startup - .CreateAppHostBuilder() - .ConfigureServices(ConfigureNativeServices) - .ConfigureUsing(startup) - .Build(); + //var host = startup + // .CreateAppHostBuilder() + // .ConfigureServices(ConfigureNativeServices) + // .ConfigureUsing(startup) + // .Build(); - Services = host.Services; + Services = mauiApp.Services; Services.InvokeLifecycleEvents(del => del(this, args)); diff --git a/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs b/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs index 3bc9fc493059..17393005e42c 100644 --- a/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs +++ b/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs @@ -8,12 +8,6 @@ namespace Microsoft.Maui { - public class MauiUIApplicationDelegate : MauiUIApplicationDelegate - where TStartup : IStartup, new() - { - protected override IStartup OnCreateStartup() => new TStartup(); - } - public abstract class MauiUIApplicationDelegate : UIApplicationDelegate, IUIApplicationDelegate { WeakReference? _virtualWindow; @@ -32,19 +26,23 @@ protected MauiUIApplicationDelegate() Current = this; } - protected abstract IStartup OnCreateStartup(); + protected abstract MauiAppBuilder CreateAppBuilder(); public override bool WillFinishLaunching(UIApplication application, NSDictionary launchOptions) { - var startup = OnCreateStartup(); + var builder = CreateAppBuilder(); + + //var startup = OnCreateStartup(); + + //var host = startup + // .CreateAppHostBuilder() + // .ConfigureServices(ConfigureNativeServices) + // .ConfigureUsing(startup) + // .Build(); - var host = startup - .CreateAppHostBuilder() - .ConfigureServices(ConfigureNativeServices) - .ConfigureUsing(startup) - .Build(); + var mauiApp = builder.Build(); - Services = host.Services; + Services = mauiApp.Services; Current.Services?.InvokeLifecycleEvents(del => del(application, launchOptions)); diff --git a/src/Core/tests/Benchmarks/Benchmarks/GetHandlersBenchmarker.cs b/src/Core/tests/Benchmarks/Benchmarks/GetHandlersBenchmarker.cs index df647c3d5396..183982d5fb3a 100644 --- a/src/Core/tests/Benchmarks/Benchmarks/GetHandlersBenchmarker.cs +++ b/src/Core/tests/Benchmarks/Benchmarks/GetHandlersBenchmarker.cs @@ -1,4 +1,5 @@ using BenchmarkDotNet.Attributes; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Maui.Hosting; namespace Microsoft.Maui.Handlers.Benchmarks @@ -6,7 +7,7 @@ namespace Microsoft.Maui.Handlers.Benchmarks [MemoryDiagnoser] public class GetHandlersBenchmarker { - IAppHost _host; + MauiApp _mauiApp; Registrar _registrar; @@ -16,8 +17,8 @@ public class GetHandlersBenchmarker [GlobalSetup(Target = nameof(GetHandlerUsingDI))] public void SetupForDI() { - _host = AppHost - .CreateDefaultBuilder() + _mauiApp = MauiApp + .CreateBuilder() .Build(); } @@ -31,9 +32,10 @@ public void SetupForRegistrar() [Benchmark] public void GetHandlerUsingDI() { + var handlers = _mauiApp.Services.GetRequiredService(); for (int i = 0; i < N; i++) { - _host.Handlers.GetHandler(); + handlers.GetHandler(); } } diff --git a/src/Core/tests/Benchmarks/Benchmarks/MauiServiceProviderBenchmarker.cs b/src/Core/tests/Benchmarks/Benchmarks/MauiServiceProviderBenchmarker.cs index 7dbcb582ca9f..4c35c4c475b5 100644 --- a/src/Core/tests/Benchmarks/Benchmarks/MauiServiceProviderBenchmarker.cs +++ b/src/Core/tests/Benchmarks/Benchmarks/MauiServiceProviderBenchmarker.cs @@ -2,14 +2,13 @@ using BenchmarkDotNet.Attributes; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Maui.Hosting; namespace Microsoft.Maui.Handlers.Benchmarks { [MemoryDiagnoser] public class MauiServiceProviderBenchmarker { - IAppHost _host; + IServiceProvider _serviceProvider; [Params(100_000)] public int N { get; set; } @@ -17,88 +16,84 @@ public class MauiServiceProviderBenchmarker [IterationSetup(Target = nameof(DefaultBuilder))] public void SetupForDefaultBuilder() { - _host = AppHost - .CreateDefaultBuilder() - .ConfigureServices((ctx, svc) => svc.AddTransient()) - .Build(); + var builder = MauiApp.CreateBuilder(); + + builder.Services.AddTransient(); + + var mauiApp = builder.Build(); + _serviceProvider = mauiApp.Services; } [IterationSetup(Target = nameof(DefaultBuilderWithConstructorInjection))] public void SetupForDefaultBuilderWithConstructorInjection() { - _host = AppHost - .CreateDefaultBuilder() - .UseMauiServiceProviderFactory(true) - .ConfigureServices((ctx, svc) => svc.AddTransient()) - .Build(); + var builder = MauiApp.CreateBuilder(); + + builder.Services.AddTransient(); + + var mauiApp = builder.Build(); + _serviceProvider = mauiApp.Services; } [IterationSetup(Target = nameof(OneConstructorParameter))] public void SetupForOneConstructorParameter() { - _host = AppHost - .CreateDefaultBuilder() - .UseMauiServiceProviderFactory(true) - .ConfigureServices((ctx, svc) => - { - svc.AddTransient(); - svc.AddTransient(); - }) - .Build(); + var builder = MauiApp.CreateBuilder(); + + builder.Services.AddTransient(); + builder.Services.AddTransient(); + + var mauiApp = builder.Build(); + _serviceProvider = mauiApp.Services; } [IterationSetup(Target = nameof(TwoConstructorParameters))] public void SetupForTwoConstructorParameters() { - _host = AppHost - .CreateDefaultBuilder() - .UseMauiServiceProviderFactory(true) - .ConfigureServices((ctx, svc) => - { - svc.AddTransient(); - svc.AddTransient(); - svc.AddTransient(); - }) - .Build(); + var builder = MauiApp.CreateBuilder(); + + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + + var mauiApp = builder.Build(); + _serviceProvider = mauiApp.Services; } [IterationSetup(Target = nameof(ExtensionsWithConstructorInjection))] public void SetupForExtensionsWithConstructorInjection() { - _host = AppHost - .CreateDefaultBuilder() - .UseServiceProviderFactory(new DIExtensionsServiceProviderFactory()) - .ConfigureServices((ctx, svc) => svc.AddTransient()) - .Build(); + var builder = MauiApp.CreateBuilder(); + + builder.Services.AddTransient(); + + var mauiApp = builder.Build(); + _serviceProvider = mauiApp.Services; } [IterationSetup(Target = nameof(ExtensionsWithOneConstructorParameter))] public void SetupForExtensionsWithOneConstructorParameter() { - _host = AppHost - .CreateDefaultBuilder() - .UseServiceProviderFactory(new DIExtensionsServiceProviderFactory()) - .ConfigureServices((ctx, svc) => - { - svc.AddTransient(); - svc.AddTransient(); - }) - .Build(); + var builder = MauiApp.CreateBuilder(); + + builder.Services.AddTransient(); + builder.Services.AddTransient(); + + var mauiApp = builder.Build(); + _serviceProvider = mauiApp.Services; } [IterationSetup(Target = nameof(ExtensionsWithTwoConstructorParameters))] public void SetupForExtensionsWithTwoConstructorParameters() { - _host = AppHost - .CreateDefaultBuilder() - .UseServiceProviderFactory(new DIExtensionsServiceProviderFactory()) - .ConfigureServices((ctx, svc) => - { - svc.AddTransient(); - svc.AddTransient(); - svc.AddTransient(); - }) - .Build(); + var builder = MauiApp.CreateBuilder(); + + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + + var mauiApp = builder.Build(); + _serviceProvider = mauiApp.Services; } [Benchmark(Baseline = true)] @@ -106,7 +101,7 @@ public void DefaultBuilder() { for (int i = 0; i < N; i++) { - _host.Services.GetService(); + _serviceProvider.GetService(); } } @@ -115,7 +110,7 @@ public void DefaultBuilderWithConstructorInjection() { for (int i = 0; i < N; i++) { - _host.Services.GetService(); + _serviceProvider.GetService(); } } @@ -124,7 +119,7 @@ public void OneConstructorParameter() { for (int i = 0; i < N; i++) { - _host.Services.GetService(); + _serviceProvider.GetService(); } } @@ -133,7 +128,7 @@ public void TwoConstructorParameters() { for (int i = 0; i < N; i++) { - _host.Services.GetService(); + _serviceProvider.GetService(); } } @@ -142,7 +137,7 @@ public void ExtensionsWithConstructorInjection() { for (int i = 0; i < N; i++) { - _host.Services.GetService(); + _serviceProvider.GetService(); } } @@ -151,7 +146,7 @@ public void ExtensionsWithOneConstructorParameter() { for (int i = 0; i < N; i++) { - _host.Services.GetService(); + _serviceProvider.GetService(); } } @@ -160,7 +155,7 @@ public void ExtensionsWithTwoConstructorParameters() { for (int i = 0; i < N; i++) { - _host.Services.GetService(); + _serviceProvider.GetService(); } } diff --git a/src/Core/tests/Benchmarks/Benchmarks/RegisterHandlersBenchmarker.cs b/src/Core/tests/Benchmarks/Benchmarks/RegisterHandlersBenchmarker.cs index 90e4a3671240..933909eb99bb 100644 --- a/src/Core/tests/Benchmarks/Benchmarks/RegisterHandlersBenchmarker.cs +++ b/src/Core/tests/Benchmarks/Benchmarks/RegisterHandlersBenchmarker.cs @@ -6,7 +6,7 @@ namespace Microsoft.Maui.Handlers.Benchmarks [MemoryDiagnoser] public class RegisterHandlersBenchmarker { - IAppHostBuilder _builder; + MauiAppBuilder _builder; Registrar _registrar; @@ -16,7 +16,7 @@ public class RegisterHandlersBenchmarker [IterationSetup(Target = nameof(RegisterHandlerUsingDI))] public void SetupForDI() { - _builder = new AppHostBuilder(); + _builder = MauiApp.CreateBuilder(); } [IterationSetup(Target = nameof(RegisterHandlerUsingRegistrar))] @@ -30,7 +30,7 @@ public void RegisterHandlerUsingDI() { for (int i = 0; i < N; i++) { - _builder.ConfigureMauiHandlers((_, handlers) => handlers.AddHandler()); + _builder.ConfigureMauiHandlers(handlers => handlers.AddHandler()); } } diff --git a/src/Core/tests/DeviceTests/Handlers/HandlerTestBase.cs b/src/Core/tests/DeviceTests/Handlers/HandlerTestBase.cs index 27711cc34ed2..34f143f179e4 100644 --- a/src/Core/tests/DeviceTests/Handlers/HandlerTestBase.cs +++ b/src/Core/tests/DeviceTests/Handlers/HandlerTestBase.cs @@ -13,23 +13,24 @@ public partial class HandlerTestBase : TestBase, IDisposable where TStub : StubBase, IView, new() { IApplication _app; - IAppHost _host; + MauiApp _mauiApp; + IServiceProvider _servicesProvider; IMauiContext _context; public HandlerTestBase() { - var appBuilder = AppHost - .CreateDefaultBuilder() + var appBuilder = MauiApp + .CreateBuilder() .ConfigureMauiHandlers(handlers => { handlers.AddHandler(typeof(SliderStub), typeof(SliderHandler)); handlers.AddHandler(typeof(ButtonStub), typeof(ButtonHandler)); }) - .ConfigureImageSources((ctx, services) => + .ConfigureImageSources(services => { services.AddService(); }) - .ConfigureFonts((ctx, fonts) => + .ConfigureFonts(fonts => { fonts.AddFont("dokdo_regular.ttf", "Dokdo"); fonts.AddFont("LobsterTwo-Regular.ttf", "Lobster Two"); @@ -38,17 +39,19 @@ public HandlerTestBase() fonts.AddFont("LobsterTwo-BoldItalic.ttf", "Lobster Two BoldItalic"); }); - _host = appBuilder.Build(); + _mauiApp = appBuilder.Build(); + _servicesProvider = _mauiApp.Services; _app = new ApplicationStub(); - _context = new ContextStub(_host.Services); + _context = new ContextStub(_servicesProvider); } public void Dispose() { - _host.Dispose(); - _host = null; + ((IDisposable)_mauiApp).Dispose(); + _mauiApp = null; + _servicesProvider = null; _app = null; _context = null; } diff --git a/src/Core/tests/DeviceTests/Platforms/Windows/App.xaml.cs b/src/Core/tests/DeviceTests/Platforms/Windows/App.xaml.cs index f27ac349885d..502fb7c5d058 100644 --- a/src/Core/tests/DeviceTests/Platforms/Windows/App.xaml.cs +++ b/src/Core/tests/DeviceTests/Platforms/Windows/App.xaml.cs @@ -22,7 +22,8 @@ public App() } } - public class MiddleApp : MauiWinUIApplication + public class MiddleApp : MauiWinUIApplication { - } + protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); + } } diff --git a/src/Core/tests/DeviceTests/Services/ImageSource/FontImageSourceServiceTests.Android.cs b/src/Core/tests/DeviceTests/Services/ImageSource/FontImageSourceServiceTests.Android.cs index aac35e3d7325..3995999ec893 100644 --- a/src/Core/tests/DeviceTests/Services/ImageSource/FontImageSourceServiceTests.Android.cs +++ b/src/Core/tests/DeviceTests/Services/ImageSource/FontImageSourceServiceTests.Android.cs @@ -32,12 +32,12 @@ public async Task GetDrawableAsync(string colorHex) { var expectedColor = Color.FromArgb(colorHex); - var host = new AppHostBuilder() + var mauiApp = MauiApp.CreateBuilder() .ConfigureFonts() .ConfigureImageSources() .Build(); - var images = host.Services.GetRequiredService(); + var images = mauiApp.Services.GetRequiredService(); var service = images.GetRequiredImageSourceService(); var imageSource = new FontImageSourceStub @@ -59,7 +59,7 @@ public async Task GetDrawableAsync(string colorHex) [Fact] public async Task GetDrawableAsyncWithCustomFont() { - var host = new AppHostBuilder() + var mauiApp = MauiApp.CreateBuilder() .ConfigureFonts(fonts => { fonts.AddFont("dokdo_regular.ttf", "Dokdo"); @@ -67,7 +67,7 @@ public async Task GetDrawableAsyncWithCustomFont() .ConfigureImageSources() .Build(); - var images = host.Services.GetRequiredService(); + var images = mauiApp.Services.GetRequiredService(); var service = images.GetRequiredImageSourceService(); var imageSource = new FontImageSourceStub diff --git a/src/Core/tests/DeviceTests/Services/ImageSource/FontImageSourceServiceTests.iOS.cs b/src/Core/tests/DeviceTests/Services/ImageSource/FontImageSourceServiceTests.iOS.cs index 0112ab6897e1..6d3d50ead35f 100644 --- a/src/Core/tests/DeviceTests/Services/ImageSource/FontImageSourceServiceTests.iOS.cs +++ b/src/Core/tests/DeviceTests/Services/ImageSource/FontImageSourceServiceTests.iOS.cs @@ -32,12 +32,12 @@ public async Task GetImageAsync(string colorHex) { var expectedColor = Color.FromArgb(colorHex); - var host = new AppHostBuilder() + var mauiApp = MauiApp.CreateBuilder() .ConfigureFonts() .ConfigureImageSources() .Build(); - var images = host.Services.GetRequiredService(); + var images = mauiApp.Services.GetRequiredService(); var service = images.GetRequiredImageSourceService(); var imageSource = new FontImageSourceStub @@ -57,7 +57,7 @@ public async Task GetImageAsync(string colorHex) [Fact] public async Task GetImageAsyncWithCustomFont() { - var host = new AppHostBuilder() + var mauiApp = MauiApp.CreateBuilder() .ConfigureFonts(fonts => { fonts.AddFont("dokdo_regular.ttf", "Dokdo"); @@ -65,7 +65,7 @@ public async Task GetImageAsyncWithCustomFont() .ConfigureImageSources() .Build(); - var images = host.Services.GetRequiredService(); + var images = mauiApp.Services.GetRequiredService(); var service = images.GetRequiredImageSourceService(); var imageSource = new FontImageSourceStub diff --git a/src/Core/tests/DeviceTests/Services/ImageSource/ImageSourceServiceTests.cs b/src/Core/tests/DeviceTests/Services/ImageSource/ImageSourceServiceTests.cs index 89147fa86a6a..34e4980f195c 100644 --- a/src/Core/tests/DeviceTests/Services/ImageSource/ImageSourceServiceTests.cs +++ b/src/Core/tests/DeviceTests/Services/ImageSource/ImageSourceServiceTests.cs @@ -89,14 +89,11 @@ public void ResultsDisposeCorrectlyAndOnce() private IImageSourceServiceProvider CreateImageSourceServiceProvider(Action configure) { - var host = new AppHostBuilder() - .UseMauiServiceProviderFactory(true) + var mauiApp = MauiApp.CreateBuilder(useDefaults: false) .ConfigureImageSources(configure) .Build(); - var services = host.Services; - - var provider = services.GetRequiredService(); + var provider = mauiApp.Services.GetRequiredService(); return provider; } diff --git a/src/Core/tests/DeviceTests/Startup.cs b/src/Core/tests/DeviceTests/Startup.cs index 439d62535382..774427cb7b69 100644 --- a/src/Core/tests/DeviceTests/Startup.cs +++ b/src/Core/tests/DeviceTests/Startup.cs @@ -4,10 +4,11 @@ namespace Microsoft.Maui.DeviceTests { - public class Startup : IStartup + public static class MauiProgram { - public void Configure(IAppHostBuilder appBuilder) + public static MauiAppBuilder CreateAppBuilder() { + var appBuilder = MauiApp.CreateBuilder(); appBuilder .ConfigureLifecycleEvents(life => { @@ -22,7 +23,7 @@ public void Configure(IAppHostBuilder appBuilder) { Assemblies = { - typeof(Startup).Assembly + typeof(MauiProgram).Assembly }, }) .UseHeadlessRunner(new HeadlessRunnerOptions @@ -30,6 +31,8 @@ public void Configure(IAppHostBuilder appBuilder) RequiresUIContext = true, }) .UseVisualRunner(); + + return appBuilder; } } } \ No newline at end of file diff --git a/src/Core/tests/UnitTests/AbstractViewHandlerTests.cs b/src/Core/tests/UnitTests/AbstractViewHandlerTests.cs index c05ebb46e823..9495c400af14 100644 --- a/src/Core/tests/UnitTests/AbstractViewHandlerTests.cs +++ b/src/Core/tests/UnitTests/AbstractViewHandlerTests.cs @@ -76,7 +76,7 @@ public void GetRequiredServiceRetrievesService() HandlerStub handlerStub = new HandlerStub(); var collection = new MauiServiceCollection(); - collection.TryAddSingleton(new MauiHandlersServiceProvider(new MauiHandlersCollection())); + collection.TryAddSingleton(new MauiHandlersServiceProvider(null)); collection.TryAddSingleton(); var provider = new MauiServiceProvider(collection, false); diff --git a/src/Core/tests/UnitTests/Hosting/HostBuilderAppConfigurationTests.cs b/src/Core/tests/UnitTests/Hosting/HostBuilderAppConfigurationTests.cs index b0f41086aa62..5e036422ec5c 100644 --- a/src/Core/tests/UnitTests/Hosting/HostBuilderAppConfigurationTests.cs +++ b/src/Core/tests/UnitTests/Hosting/HostBuilderAppConfigurationTests.cs @@ -12,17 +12,18 @@ public class HostBuilderAppConfigurationTests [Fact] public void ConfigureAppConfigurationConfiguresValues() { - var host = new AppHostBuilder() + var builder = MauiApp.CreateBuilder(); + builder.Host .ConfigureAppConfiguration((_, builder) => { builder.AddInMemoryCollection(new Dictionary { { "key 1", "value 1" }, }); - }) - .Build(); + }); + var mauiApp = builder.Build(); - var configuration = host.Services.GetRequiredService(); + var configuration = mauiApp.Services.GetRequiredService(); Assert.Equal("value 1", configuration["key 1"]); } @@ -30,7 +31,8 @@ public void ConfigureAppConfigurationConfiguresValues() [Fact] public void ConfigureAppConfigurationOverwritesValues() { - var host = new AppHostBuilder() + var builder = MauiApp.CreateBuilder(); + builder.Host .ConfigureAppConfiguration((_, builder) => { builder.AddInMemoryCollection(new Dictionary @@ -45,10 +47,10 @@ public void ConfigureAppConfigurationOverwritesValues() { { "key 1", "value a" }, }); - }) - .Build(); + }); + var mauiApp = builder.Build(); - var configuration = host.Services.GetRequiredService(); + var configuration = mauiApp.Services.GetRequiredService(); Assert.Equal("value a", configuration["key 1"]); Assert.Equal("value 2", configuration["key 2"]); @@ -59,19 +61,24 @@ public void ConfigureServicesCanUseConfig() { string value = null; - var host = new AppHostBuilder() + var builder = MauiApp.CreateBuilder(); + builder.Host .ConfigureAppConfiguration((_, builder) => { builder.AddInMemoryCollection(new Dictionary { { "key 1", "value 1" }, }); - }) + }); + + // TODO: CHECK THIS WORKS! + + builder.Host .ConfigureServices((context, services) => { value = context.Configuration["key 1"]; - }) - .Build(); + }); + var mauiApp = builder.Build(); Assert.Equal("value 1", value); } diff --git a/src/Core/tests/UnitTests/Hosting/HostBuilderFontsTests.cs b/src/Core/tests/UnitTests/Hosting/HostBuilderFontsTests.cs index 1ab01e5f13c5..60581c6832f9 100644 --- a/src/Core/tests/UnitTests/Hosting/HostBuilderFontsTests.cs +++ b/src/Core/tests/UnitTests/Hosting/HostBuilderFontsTests.cs @@ -1,6 +1,7 @@ using System; using System.IO; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Maui.Graphics; using Microsoft.Maui.Hosting; using Xunit; @@ -12,17 +13,18 @@ public class HostBuilderFontsTests [Fact] public void ConfigureFontsRegistersTheCorrectServices() { - var host = new AppHostBuilder() - .ConfigureFonts() - .Build(); + var builder = MauiApp + .CreateBuilder() + .ConfigureFonts(); + var mauiApp = builder.Build(); - var manager = host.Services.GetRequiredService(); + var manager = mauiApp.Services.GetRequiredService(); Assert.NotNull(manager); - var registrar = host.Services.GetRequiredService(); + var registrar = mauiApp.Services.GetRequiredService(); Assert.NotNull(registrar); - var loader = host.Services.GetRequiredService(); + var loader = mauiApp.Services.GetRequiredService(); Assert.NotNull(loader); } @@ -33,12 +35,13 @@ public void ConfigureFontsRegistersFonts(string filename, string alias) { var root = Path.Combine(Path.GetTempPath(), "Microsoft.Maui.UnitTests", "ConfigureFontsRegistersFonts", Guid.NewGuid().ToString()); - var host = new AppHostBuilder() - .ConfigureFonts((_, fonts) => fonts.AddEmeddedResourceFont(GetType().Assembly, filename, alias)) - .ConfigureServices((_, services) => services.AddSingleton(_ => new FileSystemEmbeddedFontLoader(root))) - .Build(); + var builder = MauiApp + .CreateBuilder() + .ConfigureFonts(fonts => fonts.AddEmeddedResourceFont(GetType().Assembly, filename, alias)); + builder.Services.AddSingleton(_ => new FileSystemEmbeddedFontLoader(root)); + var mauiApp = builder.Build(); - var registrar = host.Services.GetRequiredService(); + var registrar = mauiApp.Services.GetRequiredService(); var path = registrar.GetFont(filename); Assert.NotNull(path); @@ -59,8 +62,9 @@ public void ConfigureFontsRegistersFonts(string filename, string alias) [Fact] public void NullAssemblyForEmbeddedFontThrows() { - var builder = new AppHostBuilder() - .ConfigureFonts((_, fonts) => fonts.AddEmeddedResourceFont(null, "test.ttf")); + var builder = MauiApp + .CreateBuilder() + .ConfigureFonts(fonts => fonts.AddEmeddedResourceFont(null, "test.ttf")); var ex = Assert.Throws(() => builder.Build()); Assert.Equal("assembly", ex.ParamName); @@ -72,8 +76,9 @@ public void NullAssemblyForEmbeddedFontThrows() [InlineData(" ")] public void BadFileNameForEmbeddedFontThrows(string filename) { - var builder = new AppHostBuilder() - .ConfigureFonts((_, fonts) => fonts.AddEmeddedResourceFont(GetType().Assembly, filename)); + var builder = MauiApp + .CreateBuilder() + .ConfigureFonts(fonts => fonts.AddEmeddedResourceFont(GetType().Assembly, filename)); var ex = Assert.ThrowsAny(() => builder.Build()); Assert.Equal("filename", ex.ParamName); @@ -85,9 +90,11 @@ public void BadFileNameForEmbeddedFontThrows(string filename) [Fact] public void NullAliasForEmbeddedFontDoesNotThrow() { - new AppHostBuilder() - .ConfigureFonts((_, fonts) => fonts.AddEmeddedResourceFont(GetType().Assembly, "test.ttf", null)) - .Build(); + var builder = MauiApp + .CreateBuilder() + .ConfigureFonts(fonts => fonts.AddEmeddedResourceFont(GetType().Assembly, "test.ttf", null)); + + _ = builder.Build(); } } } \ No newline at end of file diff --git a/src/Core/tests/UnitTests/Hosting/HostBuilderHandlerTests.cs b/src/Core/tests/UnitTests/Hosting/HostBuilderHandlerTests.cs index c2489bf4f0d9..5b5578170c22 100644 --- a/src/Core/tests/UnitTests/Hosting/HostBuilderHandlerTests.cs +++ b/src/Core/tests/UnitTests/Hosting/HostBuilderHandlerTests.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Maui.Handlers; using Microsoft.Maui.Hosting; using Xunit; @@ -13,36 +12,32 @@ public class HostBuilderHandlerTests [Fact] public void CanBuildAHost() { - var host = AppHost - .CreateDefaultBuilder() + var mauiApp = MauiApp.CreateBuilder() .Build(); - Assert.NotNull(host); + Assert.NotNull(mauiApp.Services); } [Fact] public void CanGetIMauiHandlersServiceProviderFromServices() { - var host = AppHost - .CreateDefaultBuilder() + var mauiApp = MauiApp.CreateBuilder() .Build(); - Assert.NotNull(host); - Assert.NotNull(host.Services); - Assert.NotNull(host.Handlers); - Assert.IsType(host.Handlers); - Assert.Equal(host.Handlers, host.Services.GetService()); + Assert.NotNull(mauiApp.Services); + var handlers = mauiApp.Services.GetRequiredService(); + Assert.NotNull(handlers); + Assert.IsType(handlers); } [Fact] public void CanRegisterAndGetHandlerUsingType() { - var host = AppHost - .CreateDefaultBuilder() - .ConfigureMauiHandlers((_, handlers) => handlers.AddHandler()) + var mauiApp = MauiApp.CreateBuilder() + .ConfigureMauiHandlers(handlers => handlers.AddHandler()) .Build(); - var handler = host.Handlers.GetHandler(typeof(IViewStub)); + var handler = mauiApp.Services.GetRequiredService().GetHandler(typeof(IViewStub)); Assert.NotNull(handler); Assert.IsType(handler); @@ -51,12 +46,11 @@ public void CanRegisterAndGetHandlerUsingType() [Fact] public void CanRegisterAndGetHandler() { - var host = AppHost - .CreateDefaultBuilder() - .ConfigureMauiHandlers((_, handlers) => handlers.AddHandler()) + var mauiApp = MauiApp.CreateBuilder() + .ConfigureMauiHandlers(handlers => handlers.AddHandler()) .Build(); - var handler = host.Handlers.GetHandler(); + var handler = mauiApp.Services.GetRequiredService().GetHandler(); Assert.NotNull(handler); Assert.IsType(handler); @@ -65,12 +59,11 @@ public void CanRegisterAndGetHandler() [Fact] public void CanRegisterAndGetHandlerWithType() { - var host = AppHost - .CreateDefaultBuilder() - .ConfigureMauiHandlers((_, handlers) => handlers.AddHandler(typeof(IViewStub), typeof(ViewHandlerStub))) + var mauiApp = MauiApp.CreateBuilder() + .ConfigureMauiHandlers(handlers => handlers.AddHandler(typeof(IViewStub), typeof(ViewHandlerStub))) .Build(); - var handler = host.Handlers.GetHandler(typeof(IViewStub)); + var handler = mauiApp.Services.GetRequiredService().GetHandler(typeof(IViewStub)); Assert.NotNull(handler); Assert.IsType(handler); @@ -84,12 +77,11 @@ public void CanRegisterAndGetHandlerWithDictionary() { typeof(IViewStub), typeof(ViewHandlerStub) } }; - var host = AppHost - .CreateDefaultBuilder() - .ConfigureMauiHandlers((_, handlers) => handlers.AddHandlers(dic)) + var mauiApp = MauiApp.CreateBuilder() + .ConfigureMauiHandlers(handlers => handlers.AddHandlers(dic)) .Build(); - var handler = host.Handlers.GetHandler(typeof(IViewStub)); + var handler = mauiApp.Services.GetRequiredService().GetHandler(typeof(IViewStub)); Assert.NotNull(handler); Assert.IsType(handler); @@ -98,12 +90,11 @@ public void CanRegisterAndGetHandlerWithDictionary() [Fact] public void CanRegisterAndGetHandlerForConcreteType() { - var host = AppHost - .CreateDefaultBuilder() - .ConfigureMauiHandlers((_, handlers) => handlers.AddHandler()) + var mauiApp = MauiApp.CreateBuilder() + .ConfigureMauiHandlers(handlers => handlers.AddHandler()) .Build(); - var handler = host.Handlers.GetHandler(typeof(ViewStub)); + var handler = mauiApp.Services.GetRequiredService().GetHandler(typeof(ViewStub)); Assert.NotNull(handler); Assert.IsType(handler); @@ -112,17 +103,16 @@ public void CanRegisterAndGetHandlerForConcreteType() [Fact] public void CanChangeHandlerRegistration() { - var host = AppHost - .CreateDefaultBuilder() - .ConfigureMauiHandlers((_, handlers) => handlers.AddHandler()) + var mauiApp = MauiApp.CreateBuilder() + .ConfigureMauiHandlers(handlers => handlers.AddHandler()) .Build(); - var specificHandler = host.Handlers.GetHandler(typeof(ButtonStub)); + var specificHandler = mauiApp.Services.GetRequiredService().GetHandler(typeof(ButtonStub)); Assert.IsType(specificHandler); - host.Handlers.GetCollection().AddHandler(); + mauiApp.Services.GetRequiredService().GetCollection().AddHandler(); - var alternateHandler = host.Handlers.GetHandler(typeof(ButtonStub)); + var alternateHandler = mauiApp.Services.GetRequiredService().GetHandler(typeof(ButtonStub)); Assert.IsType(alternateHandler); } } diff --git a/src/Core/tests/UnitTests/Hosting/HostBuilderImageSourceTests.cs b/src/Core/tests/UnitTests/Hosting/HostBuilderImageSourceTests.cs index 92f4b5987bc8..4b8abb5e2b71 100644 --- a/src/Core/tests/UnitTests/Hosting/HostBuilderImageSourceTests.cs +++ b/src/Core/tests/UnitTests/Hosting/HostBuilderImageSourceTests.cs @@ -13,11 +13,12 @@ public class HostBuilderImageSourceTests [InlineData(typeof(FileImageSourceStub))] public void CanRetrieveFileUsingInterfaceImageSource(Type type) { - var host = new AppHostBuilder() - .ConfigureImageSources() - .Build(); + var builder = MauiApp + .CreateBuilder() + .ConfigureImageSources(); + var mauiApp = builder.Build(); - var images = host.Services.GetRequiredService(); + var images = mauiApp.Services.GetRequiredService(); Assert.NotNull(images); var imageSourceService = images.GetRequiredImageSourceService(type); @@ -28,15 +29,16 @@ public void CanRetrieveFileUsingInterfaceImageSource(Type type) [Fact] public void CanRetrieveFontUsingInterfaceImageSource() { - var host = new AppHostBuilder() + var builder = MauiApp + .CreateBuilder() .ConfigureFonts() - .ConfigureImageSources() - .Build(); + .ConfigureImageSources(); + var mauiApp = builder.Build(); - var manager = host.Services.GetRequiredService(); + var manager = mauiApp.Services.GetRequiredService(); Assert.NotNull(manager); - var images = host.Services.GetRequiredService(); + var images = mauiApp.Services.GetRequiredService(); Assert.NotNull(images); var imageSourceService = images.GetRequiredImageSourceService(); @@ -49,15 +51,16 @@ public void CanRetrieveFontUsingInterfaceImageSource() [Fact] public void CanRetrieveFontUsingConcreteImageSource() { - var host = new AppHostBuilder() + var builder = MauiApp + .CreateBuilder() .ConfigureFonts() - .ConfigureImageSources() - .Build(); + .ConfigureImageSources(); + var mauiApp = builder.Build(); - var manager = host.Services.GetRequiredService(); + var manager = mauiApp.Services.GetRequiredService(); Assert.NotNull(manager); - var images = host.Services.GetRequiredService(); + var images = mauiApp.Services.GetRequiredService(); Assert.NotNull(images); var imageSourceService = images.GetRequiredImageSourceService(); diff --git a/src/Core/tests/UnitTests/Hosting/HostBuilderServiceBuilderTests.cs b/src/Core/tests/UnitTests/Hosting/HostBuilderServiceBuilderTests.cs index a2b3eb9158c3..51412fed114d 100644 --- a/src/Core/tests/UnitTests/Hosting/HostBuilderServiceBuilderTests.cs +++ b/src/Core/tests/UnitTests/Hosting/HostBuilderServiceBuilderTests.cs @@ -16,16 +16,15 @@ public class HostBuilderServiceBuilderTests [Fact] public void MultipleServicesAreRegisteredWithoutBuilder() { - var host = new AppHostBuilder() - .UseServiceProviderFactory(new MicrosoftExtensionsServiceProviderFactory()) - .ConfigureServices((context, services) => services.AddSingleton(new MappingService("key 1", "value 1"))) - .ConfigureServices((context, services) => services.AddSingleton(new MappingService("key 2", "value 2"))) - .Build(); + var builder = MauiApp.CreateBuilder(); + builder.Services.AddSingleton(new MappingService("key 1", "value 1")); + builder.Services.AddSingleton(new MappingService("key 2", "value 2")); + var mauiApp = builder.Build(); - var services = host.Services.GetServices().ToArray(); + var mappingServices = mauiApp.Services.GetServices().ToArray(); - Assert.Equal(2, services.Length); - Assert.NotEqual(services[0], services[1]); + Assert.Equal(2, mappingServices.Length); + Assert.NotEqual(mappingServices[0], mappingServices[1]); Assert.Equal(new[] { "value 1" }, Get("key 1")); Assert.Equal(new[] { "value 2" }, Get("key 2")); @@ -33,164 +32,29 @@ public void MultipleServicesAreRegisteredWithoutBuilder() IEnumerable Get(string key) { - foreach (var service in services) + foreach (var service in mappingServices) foreach (var value in service.Get(key)) yield return value; } } - [Fact] - public void OnlyOneServiceIsRegistered() - { - var host = new AppHostBuilder() - .UseServiceProviderFactory(new MicrosoftExtensionsServiceProviderFactory()) - .ConfigureServices((context, builder) => builder.Add("key 1", "value 1")) - .ConfigureServices((context, builder) => builder.Add("key 2", "value 2")) - .Build(); - - var services = host.Services.GetServices().ToArray(); - - var service = Assert.Single(services); - - Assert.Equal(new[] { "value 1" }, service.Get("key 1")); - Assert.Equal(new[] { "value 2" }, service.Get("key 2")); - Assert.Empty(service.Get("key 3")); - } - - [Fact] - public void EventsAreInvokedOnceAndInTheRightOrder() - { - var delegateInvoked = 0; - var order = new List(); - - Assert.Equal(0, CountingServiceBuilder.Count); - - var host = new AppHostBuilder() - .ConfigureServices((context, builder) => - { - delegateInvoked++; - order.Add("Delegate1"); - - builder.BuildInvoked += (context, services) => - { - order.Add("Build"); - Assert.NotNull(context); - Assert.NotNull(services); - }; - - builder.ConfigureInvoked += (context, services) => - { - order.Add("Configure"); - Assert.NotNull(context); - Assert.NotNull(services); - }; - }) - .ConfigureServices((context, builder) => - { - delegateInvoked++; - order.Add("Delegate2"); - }) - .ConfigureServices((context, builder) => - { - delegateInvoked++; - order.Add("Delegate3"); - }) - .Build(); - - Assert.Equal(3, delegateInvoked); - Assert.Equal(new[] { "Delegate1", "Delegate2", "Delegate3", "Build", "Configure" }, order); - - Assert.Equal(1, CountingServiceBuilder.Count); - } - - [Fact] - public void EventsAreInvokedWithTheCorrectParameters() - { - var host = new AppHostBuilder() - .ConfigureServices((context, builder) => - { - Assert.NotNull(context); - Assert.NotNull(builder); - builder.BuildInvoked += (context, services) => - { - Assert.NotNull(context); - Assert.NotNull(services); - }; - builder.ConfigureInvoked += (context, services) => - { - Assert.NotNull(context); - Assert.NotNull(services); - }; - }) - .Build(); - } [Fact] public void AppConfigurationReachesBuilder() { - string buildValue = null; - string configureValue = null; - - var host = new AppHostBuilder() + var builder = MauiApp.CreateBuilder(); + builder.Host .ConfigureAppConfiguration((_, builder) => { builder.AddInMemoryCollection(new Dictionary { { "key 1", "value 1" }, }); - }) - .ConfigureServices((context, builder) => - { - builder.BuildInvoked += (context, services) => - { - buildValue = context.Configuration["key 1"]; - }; - builder.ConfigureInvoked += (context, services) => - { - configureValue = context.Configuration["key 1"]; - }; - }) - .Build(); - - Assert.Equal("value 1", buildValue); - Assert.Equal("value 1", configureValue); - } + }); - class CountingServiceBuilder : ServiceBuilderStub - { - public static int Count { get; private set; } = 0; + var appConfigValue = builder.Configuration["key 1"]; + var mauiApp = builder.Build(); - public CountingServiceBuilder() - { - Count++; - } - } - - class MultipleRegistrationBuilder : MappingService, IMauiServiceBuilder - { - public void ConfigureServices(HostBuilderContext context, IServiceCollection services) - { - services.AddSingleton(this); - } - - public void Configure(HostBuilderContext context, IServiceProvider services) - { - } - } - - class ServiceBuilderStub : IMauiServiceBuilder - { - public event Action BuildInvoked; - public event Action ConfigureInvoked; - - public void ConfigureServices(HostBuilderContext context, IServiceCollection services) - { - BuildInvoked?.Invoke(context, services); - } - - public void Configure(HostBuilderContext context, IServiceProvider services) - { - ConfigureInvoked?.Invoke(context, services); - } + Assert.Equal("value 1", appConfigValue); } class MicrosoftExtensionsServiceProviderFactory : IServiceProviderFactory diff --git a/src/Core/tests/UnitTests/Hosting/HostBuilderServicesTests.cs b/src/Core/tests/UnitTests/Hosting/HostBuilderServicesTests.cs index ebd6c50b01c6..26ab50946be0 100644 --- a/src/Core/tests/UnitTests/Hosting/HostBuilderServicesTests.cs +++ b/src/Core/tests/UnitTests/Hosting/HostBuilderServicesTests.cs @@ -13,49 +13,42 @@ public class HostBuilderServicesTests [Fact] public void CanGetServices() { - var host = new AppHostBuilder() - .Build(); + var builder = MauiApp.CreateBuilder(); + var mauiApp = builder.Build(); - Assert.NotNull(host); - Assert.NotNull(host.Services); + Assert.NotNull(mauiApp.Services); } [Fact] public void GetServiceThrowsWhenConstructorParamTypesWereNotRegistered() { - var host = new AppHostBuilder() - .UseMauiServiceProviderFactory(true) - .ConfigureServices((ctx, services) => services.AddTransient()) - .Build(); + var builder = MauiApp.CreateBuilder(); + builder.Services.AddTransient(); + var mauiApp = builder.Build(); - Assert.Throws(() => host.Services.GetService()); + Assert.Throws(() => mauiApp.Services.GetService()); } [Fact] public void GetServiceThrowsWhenNoPublicConstructors() { - var host = new AppHostBuilder() - .UseMauiServiceProviderFactory(true) - .ConfigureServices((ctx, services) => services.AddTransient()) - .Build(); + var builder = MauiApp.CreateBuilder(); + builder.Services.AddTransient(); + var mauiApp = builder.Build(); - var ex = Assert.Throws(() => host.Services.GetService()); - Assert.Contains("public or internal constructors", ex.Message); + var ex = Assert.Throws(() => mauiApp.Services.GetService()); + Assert.Contains("suitable constructor", ex.Message); } [Fact] public void GetServiceHandlesFirstOfMultipleConstructors() { - var host = new AppHostBuilder() - .UseMauiServiceProviderFactory(true) - .ConfigureServices((ctx, services) => - { - services.AddTransient(); - services.AddTransient(); - }) - .Build(); + var builder = MauiApp.CreateBuilder(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + var mauiApp = builder.Build(); - var service = host.Services.GetService(); + var service = mauiApp.Services.GetService(); var foobar = Assert.IsType(service); Assert.IsType(foobar.Foo); @@ -64,16 +57,12 @@ public void GetServiceHandlesFirstOfMultipleConstructors() [Fact] public void GetServiceHandlesSecondOfMultipleConstructors() { - var host = new AppHostBuilder() - .UseMauiServiceProviderFactory(true) - .ConfigureServices((ctx, services) => - { - services.AddTransient(); - services.AddTransient(); - }) - .Build(); + var builder = MauiApp.CreateBuilder(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + var mauiApp = builder.Build(); - var service = host.Services.GetService(); + var service = mauiApp.Services.GetService(); var foobar = Assert.IsType(service); Assert.IsType(foobar.Bar); @@ -82,15 +71,11 @@ public void GetServiceHandlesSecondOfMultipleConstructors() [Fact] public void GetServiceHandlesUsesCorrectCtor_DefaultWithNothing() { - var host = new AppHostBuilder() - .UseMauiServiceProviderFactory(true) - .ConfigureServices((ctx, services) => - { - services.AddTransient(); - }) - .Build(); + var builder = MauiApp.CreateBuilder(); + builder.Services.AddTransient(); + var mauiApp = builder.Build(); - var service = host.Services.GetService(); + var service = mauiApp.Services.GetService(); var trio = Assert.IsType(service); Assert.Null(trio.Foo); @@ -102,16 +87,12 @@ public void GetServiceHandlesUsesCorrectCtor_DefaultWithNothing() [Fact] public void GetServiceHandlesUsesCorrectCtor_DefaultWithBar() { - var host = new AppHostBuilder() - .UseMauiServiceProviderFactory(true) - .ConfigureServices((ctx, services) => - { - services.AddTransient(); - services.AddTransient(); - }) - .Build(); + var builder = MauiApp.CreateBuilder(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + var mauiApp = builder.Build(); - var service = host.Services.GetService(); + var service = mauiApp.Services.GetService(); var trio = Assert.IsType(service); Assert.Null(trio.Foo); @@ -123,16 +104,12 @@ public void GetServiceHandlesUsesCorrectCtor_DefaultWithBar() [Fact] public void GetServiceHandlesUsesCorrectCtor_Foo() { - var host = new AppHostBuilder() - .UseMauiServiceProviderFactory(true) - .ConfigureServices((ctx, services) => - { - services.AddTransient(); - services.AddTransient(); - }) - .Build(); + var builder = MauiApp.CreateBuilder(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + var mauiApp = builder.Build(); - var service = host.Services.GetService(); + var service = mauiApp.Services.GetService(); var trio = Assert.IsType(service); Assert.IsType(trio.Foo); @@ -144,17 +121,13 @@ public void GetServiceHandlesUsesCorrectCtor_Foo() [Fact] public void GetServiceHandlesUsesCorrectCtor_FooWithCat() { - var host = new AppHostBuilder() - .UseMauiServiceProviderFactory(true) - .ConfigureServices((ctx, services) => - { - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - }) - .Build(); - - var service = host.Services.GetService(); + var builder = MauiApp.CreateBuilder(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + var mauiApp = builder.Build(); + + var service = mauiApp.Services.GetService(); var trio = Assert.IsType(service); Assert.IsType(trio.Foo); @@ -166,17 +139,13 @@ public void GetServiceHandlesUsesCorrectCtor_FooWithCat() [Fact] public void GetServiceHandlesUsesCorrectCtor_FooBar() { - var host = new AppHostBuilder() - .UseMauiServiceProviderFactory(true) - .ConfigureServices((ctx, services) => - { - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - }) - .Build(); - - var service = host.Services.GetService(); + var builder = MauiApp.CreateBuilder(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + var mauiApp = builder.Build(); + + var service = mauiApp.Services.GetService(); var trio = Assert.IsType(service); Assert.IsType(trio.Foo); @@ -188,18 +157,14 @@ public void GetServiceHandlesUsesCorrectCtor_FooBar() [Fact] public void GetServiceHandlesUsesCorrectCtor_FooBarCat() { - var host = new AppHostBuilder() - .UseMauiServiceProviderFactory(true) - .ConfigureServices((ctx, services) => - { - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - }) - .Build(); - - var service = host.Services.GetService(); + var builder = MauiApp.CreateBuilder(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + var mauiApp = builder.Build(); + + var service = mauiApp.Services.GetService(); var trio = Assert.IsType(service); Assert.IsType(trio.Foo); @@ -211,17 +176,13 @@ public void GetServiceHandlesUsesCorrectCtor_FooBarCat() [Fact] public void GetServiceCanReturnTypesThatHaveConstructorParams() { - var host = new AppHostBuilder() - .UseMauiServiceProviderFactory(true) - .ConfigureServices((ctx, services) => - { - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - }) - .Build(); - - var service = host.Services.GetService(); + var builder = MauiApp.CreateBuilder(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + var mauiApp = builder.Build(); + + var service = mauiApp.Services.GetService(); var foobar = Assert.IsType(service); Assert.IsType(foobar.Foo); @@ -231,15 +192,11 @@ public void GetServiceCanReturnTypesThatHaveConstructorParams() [Fact] public void GetServiceCanReturnTypesThatHaveUnregisteredConstructorParamsButHaveDefaultValues() { - var host = new AppHostBuilder() - .UseMauiServiceProviderFactory(true) - .ConfigureServices((ctx, services) => - { - services.AddTransient(); - }) - .Build(); + var builder = MauiApp.CreateBuilder(); + builder.Services.AddTransient(); + var mauiApp = builder.Build(); - var foo = host.Services.GetService(); + var foo = mauiApp.Services.GetService(); Assert.NotNull(foo); @@ -251,16 +208,12 @@ public void GetServiceCanReturnTypesThatHaveUnregisteredConstructorParamsButHave [Fact] public void GetServiceCanReturnTypesThatHaveRegisteredConstructorParamsAndHaveDefaultValues() { - var host = new AppHostBuilder() - .UseMauiServiceProviderFactory(true) - .ConfigureServices((ctx, services) => - { - services.AddTransient(); - services.AddTransient(); - }) - .Build(); + var builder = MauiApp.CreateBuilder(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + var mauiApp = builder.Build(); - var foo = host.Services.GetService(); + var foo = mauiApp.Services.GetService(); Assert.NotNull(foo); @@ -273,15 +226,11 @@ public void GetServiceCanReturnTypesThatHaveRegisteredConstructorParamsAndHaveDe [Fact] public void GetServiceCanReturnTypesThatHaveSystemDefaultValues() { - var host = new AppHostBuilder() - .UseMauiServiceProviderFactory(true) - .ConfigureServices((ctx, services) => - { - services.AddTransient(); - }) - .Build(); + var builder = MauiApp.CreateBuilder(); + builder.Services.AddTransient(); + var mauiApp = builder.Build(); - var foo = host.Services.GetService(); + var foo = mauiApp.Services.GetService(); Assert.NotNull(foo); @@ -293,17 +242,13 @@ public void GetServiceCanReturnTypesThatHaveSystemDefaultValues() [Fact] public void GetServiceCanReturnEnumerableParams() { - var host = new AppHostBuilder() - .UseMauiServiceProviderFactory(true) - .ConfigureServices((ctx, services) => - { - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - }) - .Build(); - - var service = host.Services.GetService(); + var builder = MauiApp.CreateBuilder(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + var mauiApp = builder.Build(); + + var service = mauiApp.Services.GetService(); var foobar = Assert.IsType(service); var serviceTypes = foobar.Foos @@ -316,75 +261,63 @@ public void GetServiceCanReturnEnumerableParams() [Fact] public void WillRetrieveDifferentTransientServices() { - var host = new AppHostBuilder() - .ConfigureServices((ctx, services) => services.AddTransient()) - .Build(); + var builder = MauiApp.CreateBuilder(); + builder.Services.AddTransient(); + var mauiApp = builder.Build(); - AssertTransient(host.Services); + AssertTransient(mauiApp.Services); } [Fact] public void WillRetrieveSameSingletonServices() { - var host = new AppHostBuilder() - .ConfigureServices((ctx, services) => services.AddSingleton()) - .Build(); + var builder = MauiApp.CreateBuilder(); + builder.Services.AddSingleton(); + var mauiApp = builder.Build(); - AssertSingleton(host.Services); + AssertSingleton(mauiApp.Services); } [Fact] public void WillRetrieveMixedServices() { - var host = new AppHostBuilder() - .ConfigureServices((ctx, services) => - { - services.AddSingleton(); - services.AddTransient(); - }) - .Build(); - - AssertSingleton(host.Services); - AssertTransient(host.Services); + var builder = MauiApp.CreateBuilder(); + builder.Services.AddSingleton(); + builder.Services.AddTransient(); + var mauiApp = builder.Build(); + + AssertSingleton(mauiApp.Services); + AssertTransient(mauiApp.Services); } [Fact] public void WillRetrieveEnumerables() { - var host = new AppHostBuilder() - .ConfigureServices((ctx, services) => - { - services.AddTransient(); - services.AddTransient(); - }) - .Build(); - - var services = host.Services + var builder = MauiApp.CreateBuilder(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + var mauiApp = builder.Build(); + + var fooServices = mauiApp.Services .GetServices() .ToArray(); - Assert.Equal(2, services.Length); + Assert.Equal(2, fooServices.Length); - var serviceTypes = services + var serviceTypes = fooServices .Select(s => s.GetType().FullName) .ToArray(); Assert.Contains(typeof(FooService).FullName, serviceTypes); Assert.Contains(typeof(FooService2).FullName, serviceTypes); } - [Theory] - //[InlineData(true)] // TODO: The MAUI provider does not support generic args - [InlineData(false)] - public void CanCreateLogger(bool ctorInjection) + [Fact] + public void CanCreateLogger() { - var host = new AppHostBuilder() - .UseMauiServiceProviderFactory(ctorInjection) - .ConfigureServices((ctx, services) => - { - services.AddLogging(logging => logging.AddConsole()); - }) - .Build(); - - var factory = host.Services.GetRequiredService(); + var builder = MauiApp.CreateBuilder(); + builder.Services.AddLogging(logging => logging.AddConsole()); + var mauiApp = builder.Build(); + + var factory = mauiApp.Services.GetRequiredService(); var logger = factory.CreateLogger(); diff --git a/src/Core/tests/UnitTests/ImageSource/ImageSourceServiceTests.cs b/src/Core/tests/UnitTests/ImageSource/ImageSourceServiceTests.cs index 02196e7b4278..2c5769e463be 100644 --- a/src/Core/tests/UnitTests/ImageSource/ImageSourceServiceTests.cs +++ b/src/Core/tests/UnitTests/ImageSource/ImageSourceServiceTests.cs @@ -27,15 +27,11 @@ public void ResolvesToConcreteTypeOverInterface() private IImageSourceServiceProvider CreateImageSourceServiceProvider(Action configure) { - - var host = new AppHostBuilder() - .UseMauiServiceProviderFactory(true) + var mauiApp = MauiApp.CreateBuilder() .ConfigureImageSources(configure) .Build(); - var services = host.Services; - - var provider = services.GetRequiredService(); + var provider = mauiApp.Services.GetRequiredService(); return provider; } diff --git a/src/Core/tests/UnitTests/LifecycleEvents/LifecycleEventsTests.cs b/src/Core/tests/UnitTests/LifecycleEvents/LifecycleEventsTests.cs index 1350706399ee..a15c4916e544 100644 --- a/src/Core/tests/UnitTests/LifecycleEvents/LifecycleEventsTests.cs +++ b/src/Core/tests/UnitTests/LifecycleEvents/LifecycleEventsTests.cs @@ -11,22 +11,22 @@ public class LifecycleEventsTests [Fact] public void ConfigureLifecycleEventsRegistersService() { - var host = new AppHostBuilder() - .ConfigureLifecycleEvents((_, builder) => { }) + var mauiApp = MauiApp.CreateBuilder() + .ConfigureLifecycleEvents(builder => { }) .Build(); - var service = host.Services.GetRequiredService(); + var service = mauiApp.Services.GetRequiredService(); Assert.NotNull(service); } [Fact] public void CanAddCustomEvent() { - var host = new AppHostBuilder() - .ConfigureLifecycleEvents((_, builder) => builder.AddEvent("TestEvent", () => { })) + var mauiApp = MauiApp.CreateBuilder() + .ConfigureLifecycleEvents(builder => builder.AddEvent("TestEvent", () => { })) .Build(); - var service = host.Services.GetRequiredService(); + var service = mauiApp.Services.GetRequiredService(); Assert.True(service.ContainsEvent("TestEvent")); } @@ -34,11 +34,11 @@ public void CanAddCustomEvent() [Fact] public void CanAddDelegateEvent() { - var host = new AppHostBuilder() - .ConfigureLifecycleEvents((_, builder) => builder.AddEvent("TestEvent", param => param++)) + var mauiApp = MauiApp.CreateBuilder() + .ConfigureLifecycleEvents(builder => builder.AddEvent("TestEvent", param => param++)) .Build(); - var service = host.Services.GetRequiredService(); + var service = mauiApp.Services.GetRequiredService(); Assert.True(service.ContainsEvent("TestEvent")); } @@ -48,11 +48,11 @@ public void InvokingUnregisteredEventsDoesNotThrow() { var eventFired = 0; - var host = new AppHostBuilder() - .ConfigureLifecycleEvents((_, builder) => builder.AddEvent("TestEvent", () => eventFired++)) + var mauiApp = MauiApp.CreateBuilder() + .ConfigureLifecycleEvents(builder => builder.AddEvent("TestEvent", () => eventFired++)) .Build(); - var service = host.Services.GetRequiredService(); + var service = mauiApp.Services.GetRequiredService(); service.InvokeEvents("AnotherEvent"); @@ -64,11 +64,11 @@ public void EventsFireExactlyOnce() { var eventFired = 0; - var host = new AppHostBuilder() - .ConfigureLifecycleEvents((_, builder) => builder.AddEvent("TestEvent", () => eventFired++)) + var mauiApp = MauiApp.CreateBuilder() + .ConfigureLifecycleEvents(builder => builder.AddEvent("TestEvent", () => eventFired++)) .Build(); - var service = host.Services.GetRequiredService(); + var service = mauiApp.Services.GetRequiredService(); service.InvokeEvents("TestEvent"); @@ -81,11 +81,11 @@ public void DelegateEventsFireExactlyOnce() var eventFired = 0; var newValue = 0; - var host = new AppHostBuilder() - .ConfigureLifecycleEvents((_, builder) => builder.AddEvent("TestEvent", param => param + 1)) + var mauiApp = MauiApp.CreateBuilder() + .ConfigureLifecycleEvents(builder => builder.AddEvent("TestEvent", param => param + 1)) .Build(); - var service = host.Services.GetRequiredService(); + var service = mauiApp.Services.GetRequiredService(); service.InvokeEvents("TestEvent", del => { @@ -102,11 +102,11 @@ public void EventsMustBeInvokedUsingExactDelegate() { var eventFired = 0; - var host = new AppHostBuilder() - .ConfigureLifecycleEvents((_, builder) => builder.AddEvent("TestEvent", () => eventFired++)) + var mauiApp = MauiApp.CreateBuilder() + .ConfigureLifecycleEvents(builder => builder.AddEvent("TestEvent", () => eventFired++)) .Build(); - var service = host.Services.GetRequiredService(); + var service = mauiApp.Services.GetRequiredService(); Assert.True(service.ContainsEvent("TestEvent")); Assert.Empty(service.GetEventDelegates("TestEvent")); @@ -122,12 +122,12 @@ public void CanAddMultipleEventsViaMultipleConfigureLifecycleEvents() var event1Fired = 0; var event2Fired = 0; - var host = new AppHostBuilder() - .ConfigureLifecycleEvents((_, builder) => builder.AddEvent("TestEvent", () => event1Fired++)) - .ConfigureLifecycleEvents((_, builder) => builder.AddEvent("TestEvent", () => event2Fired++)) + var mauiApp = MauiApp.CreateBuilder() + .ConfigureLifecycleEvents(builder => builder.AddEvent("TestEvent", () => event1Fired++)) + .ConfigureLifecycleEvents(builder => builder.AddEvent("TestEvent", () => event2Fired++)) .Build(); - var service = host.Services.GetRequiredService(); + var service = mauiApp.Services.GetRequiredService(); service.InvokeEvents("TestEvent"); @@ -141,15 +141,15 @@ public void CanAddMultipleEventsViaBuilder() var event1Fired = 0; var event2Fired = 0; - var host = new AppHostBuilder() - .ConfigureLifecycleEvents((_, builder) => + var mauiApp = MauiApp.CreateBuilder() + .ConfigureLifecycleEvents(builder => { builder.AddEvent("TestEvent", () => event1Fired++); builder.AddEvent("TestEvent", () => event2Fired++); }) .Build(); - var service = host.Services.GetRequiredService(); + var service = mauiApp.Services.GetRequiredService(); service.InvokeEvents("TestEvent"); diff --git a/src/Essentials/samples/Samples/Platforms/Android/MainApplication.cs b/src/Essentials/samples/Samples/Platforms/Android/MainApplication.cs index 534e412216e6..53a54700bb88 100644 --- a/src/Essentials/samples/Samples/Platforms/Android/MainApplication.cs +++ b/src/Essentials/samples/Samples/Platforms/Android/MainApplication.cs @@ -7,10 +7,12 @@ namespace Samples.Droid { [Application] - public class MainApplication : MauiApplication + public class MainApplication : MauiApplication { public MainApplication(IntPtr handle, JniHandleOwnership ownership) : base(handle, ownership) { } + + protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); } } \ No newline at end of file diff --git a/src/Essentials/samples/Samples/Platforms/MacCatalyst/AppDelegate.cs b/src/Essentials/samples/Samples/Platforms/MacCatalyst/AppDelegate.cs index d7238aaad230..c1c1d351aae1 100644 --- a/src/Essentials/samples/Samples/Platforms/MacCatalyst/AppDelegate.cs +++ b/src/Essentials/samples/Samples/Platforms/MacCatalyst/AppDelegate.cs @@ -4,7 +4,8 @@ namespace Samples.iOS { [Register(nameof(AppDelegate))] - public partial class AppDelegate : MauiUIApplicationDelegate + public partial class AppDelegate : MauiUIApplicationDelegate { + protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); } } \ No newline at end of file diff --git a/src/Essentials/samples/Samples/Platforms/Windows/App.xaml.cs b/src/Essentials/samples/Samples/Platforms/Windows/App.xaml.cs index 1b81e6b1062c..01ae020c3eeb 100644 --- a/src/Essentials/samples/Samples/Platforms/Windows/App.xaml.cs +++ b/src/Essentials/samples/Samples/Platforms/Windows/App.xaml.cs @@ -2,8 +2,9 @@ namespace Samples.UWP { - public class MiddleApp : MauiWinUIApplication + public class MiddleApp : MauiWinUIApplication { + protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); } public partial class App : MiddleApp diff --git a/src/Essentials/samples/Samples/Platforms/iOS/AppDelegate.cs b/src/Essentials/samples/Samples/Platforms/iOS/AppDelegate.cs index d7238aaad230..c1c1d351aae1 100644 --- a/src/Essentials/samples/Samples/Platforms/iOS/AppDelegate.cs +++ b/src/Essentials/samples/Samples/Platforms/iOS/AppDelegate.cs @@ -4,7 +4,8 @@ namespace Samples.iOS { [Register(nameof(AppDelegate))] - public partial class AppDelegate : MauiUIApplicationDelegate + public partial class AppDelegate : MauiUIApplicationDelegate { + protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); } } \ No newline at end of file diff --git a/src/Essentials/samples/Samples/Startup.cs b/src/Essentials/samples/Samples/Startup.cs index b83902b0d15d..fa138100c4e3 100644 --- a/src/Essentials/samples/Samples/Startup.cs +++ b/src/Essentials/samples/Samples/Startup.cs @@ -1,14 +1,15 @@ using Microsoft.Maui; using Microsoft.Maui.Controls.Hosting; -using Microsoft.Maui.Hosting; using Microsoft.Maui.LifecycleEvents; namespace Samples { - public class Startup : IStartup + public static class MauiProgram { - public void Configure(IAppHostBuilder appBuilder) + public static MauiAppBuilder CreateAppBuilder() { + var appBuilder = MauiApp.CreateBuilder(); + #if WINDOWS Microsoft.Maui.Essentials.Platform.MapServiceToken = "RJHqIE53Onrqons5CNOx~FrDr3XhjDTyEXEjng-CRoA~Aj69MhNManYUKxo6QcwZ0wmXBtyva0zwuHB04rFYAPf7qqGJ5cHb03RCDw1jIW8l"; @@ -31,9 +32,11 @@ public void Configure(IAppHostBuilder appBuilder) .AddWindows(windows => windows .OnLaunched((app, e) => Microsoft.Maui.Essentials.Platform.OnLaunched(e))); - #endif +#endif }) .UseMauiApp(); + + return appBuilder; } } } diff --git a/src/Essentials/test/DeviceTests/Platforms/Windows/App.xaml.cs b/src/Essentials/test/DeviceTests/Platforms/Windows/App.xaml.cs index b62e3042cd07..6200a12bb0e6 100644 --- a/src/Essentials/test/DeviceTests/Platforms/Windows/App.xaml.cs +++ b/src/Essentials/test/DeviceTests/Platforms/Windows/App.xaml.cs @@ -22,7 +22,8 @@ public App() } } - public class MiddleApp : MauiWinUIApplication + public class MiddleApp : MauiWinUIApplication { - } + protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); + } } diff --git a/src/Essentials/test/DeviceTests/Startup.cs b/src/Essentials/test/DeviceTests/Startup.cs index 2430f206b736..67bcd5e510bc 100644 --- a/src/Essentials/test/DeviceTests/Startup.cs +++ b/src/Essentials/test/DeviceTests/Startup.cs @@ -5,10 +5,11 @@ namespace Microsoft.Maui.Essentials.DeviceTests { - public class Startup : IStartup + public static class MauiProgram { - public void Configure(IAppHostBuilder appBuilder) + public static MauiAppBuilder CreateAppBuilder() { + var appBuilder = MauiApp.CreateBuilder(); appBuilder .ConfigureLifecycleEvents(life => { @@ -26,7 +27,7 @@ public void Configure(IAppHostBuilder appBuilder) { Assemblies = { - typeof(Startup).Assembly + typeof(MauiProgram).Assembly }, SkipCategories = Traits .GetSkipTraits() @@ -40,6 +41,8 @@ public void Configure(IAppHostBuilder appBuilder) RequiresUIContext = true, }) .UseVisualRunner(); + + return appBuilder; } } } \ No newline at end of file diff --git a/src/TestUtils/samples/DeviceTests.Sample/Platforms/Windows/App.xaml.cs b/src/TestUtils/samples/DeviceTests.Sample/Platforms/Windows/App.xaml.cs index fcb61a40d1d9..c48b0b8f25d4 100644 --- a/src/TestUtils/samples/DeviceTests.Sample/Platforms/Windows/App.xaml.cs +++ b/src/TestUtils/samples/DeviceTests.Sample/Platforms/Windows/App.xaml.cs @@ -22,7 +22,8 @@ public App() } } - public class MiddleApp : MauiWinUIApplication + public class MiddleApp : MauiWinUIApplication { - } + protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); + } } diff --git a/src/TestUtils/samples/DeviceTests.Sample/Startup.cs b/src/TestUtils/samples/DeviceTests.Sample/Startup.cs index fb9a2a0549ae..5790ba15e859 100644 --- a/src/TestUtils/samples/DeviceTests.Sample/Startup.cs +++ b/src/TestUtils/samples/DeviceTests.Sample/Startup.cs @@ -1,18 +1,18 @@ -using Microsoft.Maui.Hosting; -using Microsoft.Maui.TestUtils.DeviceTests.Runners; +using Microsoft.Maui.TestUtils.DeviceTests.Runners; namespace Microsoft.Maui.TestUtils.DeviceTests.Sample { - public class Startup : IStartup + public static class MauiProgram { - public void Configure(IAppHostBuilder appBuilder) + public static MauiAppBuilder CreateAppBuilder() { + var appBuilder = MauiApp.CreateBuilder(); appBuilder .ConfigureTests(new TestOptions { Assemblies = { - typeof(Startup).Assembly + typeof(MauiProgram).Assembly }, }) .UseHeadlessRunner(new HeadlessRunnerOptions @@ -20,6 +20,8 @@ public void Configure(IAppHostBuilder appBuilder) RequiresUIContext = true, }) .UseVisualRunner(); + + return appBuilder; } } } \ No newline at end of file diff --git a/src/TestUtils/src/DeviceTests.Runners.SourceGen/RunnerGenerator.cs b/src/TestUtils/src/DeviceTests.Runners.SourceGen/RunnerGenerator.cs index e99f9fddd90a..e86aeca95f92 100644 --- a/src/TestUtils/src/DeviceTests.Runners.SourceGen/RunnerGenerator.cs +++ b/src/TestUtils/src/DeviceTests.Runners.SourceGen/RunnerGenerator.cs @@ -85,7 +85,8 @@ protected void AddSource(string filename, string contents) string GenerateAndroidSource() { - var startupName = "Startup"; + var mauiProgramName = "MauiProgram"; + var mauiProgramFullName = @"global::" + RootNamespace + "." + mauiProgramName; var splash = ContainsSplashScreen ? @"Theme = ""@style/Maui.SplashTheme""," : ""; var appName = "MainApplication"; @@ -99,12 +100,14 @@ string GenerateAndroidSource() namespace " + RootNamespace + @" { [global::Android.App.Application] - partial class " + appName + @" : global::Microsoft.Maui.MauiApplication + partial class " + appName + @" : global::Microsoft.Maui.MauiApplication { public " + appName + @"(global::System.IntPtr handle, global::Android.Runtime.JniHandleOwnership ownership) : base(handle, ownership) { } + + protected override global::Microsoft.Maui.MauiAppBuilder CreateAppBuilder() => " + mauiProgramFullName + @".CreateAppBuilder(); } } #endif @@ -163,7 +166,8 @@ public partial class " + headlessActivityName + @" : global::Microsoft.Maui.Test string GenerateIosSource() { - var startupName = "Startup"; + var mauiProgramName = "MauiProgram"; + var mauiProgramFullName = @"global::" + RootNamespace + "." + mauiProgramName; var visualDelegateName = "VisualRunnerAppDelegate"; var headlessDelegateName = "HeadlessRunnerAppDelegate"; @@ -196,8 +200,9 @@ static void Main(global::System.String[] args) namespace " + RootNamespace + @" { [global::Foundation.Register(""" + visualDelegateName + @""")] - partial class " + visualDelegateName + @" : global::Microsoft.Maui.MauiUIApplicationDelegate + partial class " + visualDelegateName + @" : global::Microsoft.Maui.MauiUIApplicationDelegate { + protected override global::Microsoft.Maui.MauiAppBuilder CreateAppBuilder() => " + mauiProgramFullName + @".CreateAppBuilder(); } } #endif @@ -206,8 +211,10 @@ partial class " + visualDelegateName + @" : global::Microsoft.Maui.MauiUIApplica namespace " + RootNamespace + @" { [global::Foundation.Register(""" + headlessDelegateName + @""")] - partial class " + headlessDelegateName + @" : global::Microsoft.Maui.TestUtils.DeviceTests.Runners.HeadlessRunner.MauiTestApplicationDelegate + partial class " + headlessDelegateName + @" : global::Microsoft.Maui.TestUtils.DeviceTests.Runners.HeadlessRunner.MauiTestApplicationDelegate { + + protected override global::Microsoft.Maui.MauiAppBuilder CreateAppBuilder() => " + mauiProgramFullName + @".CreateAppBuilder(); } } #endif diff --git a/src/TestUtils/src/DeviceTests.Runners/AppHostBuilderExtensions.cs b/src/TestUtils/src/DeviceTests.Runners/AppHostBuilderExtensions.cs index c5036fc44709..1159069966c2 100644 --- a/src/TestUtils/src/DeviceTests.Runners/AppHostBuilderExtensions.cs +++ b/src/TestUtils/src/DeviceTests.Runners/AppHostBuilderExtensions.cs @@ -10,14 +10,14 @@ namespace Microsoft.Maui.TestUtils.DeviceTests.Runners { public static class AppHostBuilderExtensions { - public static IAppHostBuilder ConfigureTests(this IAppHostBuilder appHostBuilder, TestOptions options) + public static MauiAppBuilder ConfigureTests(this MauiAppBuilder appHostBuilder, TestOptions options) { - appHostBuilder.ConfigureServices(services => services.AddSingleton(options)); + appHostBuilder.Services.AddSingleton(options); return appHostBuilder; } - public static IAppHostBuilder UseVisualRunner(this IAppHostBuilder appHostBuilder) + public static MauiAppBuilder UseVisualRunner(this MauiAppBuilder appHostBuilder) { appHostBuilder.UseMauiApp(svc => new MauiVisualRunnerApp( svc.GetRequiredService(), @@ -26,18 +26,15 @@ public static IAppHostBuilder UseVisualRunner(this IAppHostBuilder appHostBuilde return appHostBuilder; } - public static IAppHostBuilder UseHeadlessRunner(this IAppHostBuilder appHostBuilder, HeadlessRunnerOptions options) + public static MauiAppBuilder UseHeadlessRunner(this MauiAppBuilder appHostBuilder, HeadlessRunnerOptions options) { - appHostBuilder.ConfigureServices(services => - { - services.AddSingleton(options); + appHostBuilder.Services.AddSingleton(options); #if __ANDROID__ || __IOS__ || MACCATALYST - services.AddTransient(svc => new HeadlessTestRunner( + appHostBuilder.Services.AddTransient(svc => new HeadlessTestRunner( svc.GetRequiredService(), svc.GetRequiredService())); #endif - }); return appHostBuilder; } diff --git a/src/TestUtils/src/DeviceTests.Runners/HeadlessRunner/iOS/MauiTestApplicationDelegate.cs b/src/TestUtils/src/DeviceTests.Runners/HeadlessRunner/iOS/MauiTestApplicationDelegate.cs index 60231f656bb8..e9f3249be9ac 100644 --- a/src/TestUtils/src/DeviceTests.Runners/HeadlessRunner/iOS/MauiTestApplicationDelegate.cs +++ b/src/TestUtils/src/DeviceTests.Runners/HeadlessRunner/iOS/MauiTestApplicationDelegate.cs @@ -9,20 +9,6 @@ namespace Microsoft.Maui.TestUtils.DeviceTests.Runners.HeadlessRunner { - public abstract class MauiTestApplicationDelegate : MauiTestApplicationDelegate - where TStartup : IStartup, new() - { - protected override IAppHost OnBuildAppHost() - { - var startup = new TStartup(); - - return startup - .CreateAppHostBuilder() - .ConfigureUsing(startup) - .Build(); - } - } - public abstract class MauiTestApplicationDelegate : UIApplicationDelegate { public static bool IsHeadlessRunner(string[] args) @@ -46,13 +32,14 @@ protected MauiTestApplicationDelegate() public override UIWindow? Window { get; set; } - protected abstract IAppHost OnBuildAppHost(); + protected abstract MauiAppBuilder CreateAppBuilder(); public override bool WillFinishLaunching(UIApplication application, NSDictionary launchOptions) { - var host = OnBuildAppHost(); + var builder = CreateAppBuilder(); + var mauiApp = builder.Build(); + Services = mauiApp.Services; - Services = host.Services; Options = Services.GetRequiredService(); RunnerOptions = Services.GetRequiredService(); From f14bbdfb5f2ac2592947554c931e3fc6a488aacd Mon Sep 17 00:00:00 2001 From: Eilon Lipton Date: Mon, 23 Aug 2021 23:57:24 -0700 Subject: [PATCH 2/7] Have user code return the built MauiApp Instead of returning the builder. --- src/Compatibility/ControlGallery/src/Core/Startup.cs | 8 +++++++- src/Compatibility/ControlGallery/src/WinUI/App.xaml.cs | 2 +- .../ControlGallery/src/WinUI/WinUIStartup.cs | 4 ++-- src/Compatibility/ControlGallery/src/iOS/AppDelegate.cs | 2 +- .../samples/Controls.Sample.Droid/MainApplication.cs | 2 +- .../samples/Controls.Sample.MacCatalyst/AppDelegate.cs | 2 +- .../Platforms/Android/MainApplication.cs | 2 +- .../Platforms/MacCatalyst/AppDelegate.cs | 2 +- .../Platforms/iOS/AppDelegate.cs | 2 +- src/Controls/samples/Controls.Sample.Profiling/Startup.cs | 4 ++-- .../Platforms/Android/MainApplication.cs | 2 +- .../Platforms/MacCatalyst/AppDelegate.cs | 2 +- .../Platforms/Windows/App.xaml.cs | 2 +- .../Platforms/iOS/AppDelegate.cs | 2 +- .../samples/Controls.Sample.SingleProject/Startup.cs | 4 ++-- src/Controls/samples/Controls.Sample.WinUI/App.xaml.cs | 2 +- src/Controls/samples/Controls.Sample.iOS/AppDelegate.cs | 2 +- src/Controls/samples/Controls.Sample/Startup.cs | 4 ++-- src/Core/src/Platform/Android/MauiApplication.cs | 6 ++---- src/Core/src/Platform/Windows/MauiWinUIApplication.cs | 5 ++--- src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs | 6 ++---- src/Core/tests/DeviceTests/Platforms/Windows/App.xaml.cs | 2 +- src/Core/tests/DeviceTests/Startup.cs | 4 ++-- .../samples/Samples/Platforms/Android/MainApplication.cs | 2 +- .../samples/Samples/Platforms/MacCatalyst/AppDelegate.cs | 2 +- .../samples/Samples/Platforms/Windows/App.xaml.cs | 2 +- .../samples/Samples/Platforms/iOS/AppDelegate.cs | 2 +- src/Essentials/samples/Samples/Startup.cs | 4 ++-- .../test/DeviceTests/Platforms/Windows/App.xaml.cs | 2 +- src/Essentials/test/DeviceTests/Startup.cs | 4 ++-- .../DeviceTests.Sample/Platforms/Windows/App.xaml.cs | 2 +- src/TestUtils/samples/DeviceTests.Sample/Startup.cs | 4 ++-- .../src/DeviceTests.Runners.SourceGen/RunnerGenerator.cs | 6 +++--- .../HeadlessRunner/iOS/MauiTestApplicationDelegate.cs | 5 ++--- 34 files changed, 54 insertions(+), 54 deletions(-) diff --git a/src/Compatibility/ControlGallery/src/Core/Startup.cs b/src/Compatibility/ControlGallery/src/Core/Startup.cs index 61dd71562ade..3fc4bf7e8a06 100644 --- a/src/Compatibility/ControlGallery/src/Core/Startup.cs +++ b/src/Compatibility/ControlGallery/src/Core/Startup.cs @@ -10,7 +10,13 @@ public static class MauiProgram { internal static bool UseBlazor = false; - public static MauiAppBuilder CreateAppBuilder() + public static MauiApp CreateMauiApp() + { + var builder = CreateMauiAppBuilder(); + return builder.Build(); + } + + public static MauiAppBuilder CreateMauiAppBuilder() { var builder = MauiApp.CreateBuilder(); builder diff --git a/src/Compatibility/ControlGallery/src/WinUI/App.xaml.cs b/src/Compatibility/ControlGallery/src/WinUI/App.xaml.cs index 38b0d670ba6b..4276fb0079c0 100644 --- a/src/Compatibility/ControlGallery/src/WinUI/App.xaml.cs +++ b/src/Compatibility/ControlGallery/src/WinUI/App.xaml.cs @@ -16,6 +16,6 @@ public App() InitializeComponent(); } - protected override MauiAppBuilder CreateAppBuilder() => WinUIMauiProgram.CreateAppBuilder(); + protected override MauiApp CreateMauiApp() => WinUIMauiProgram.CreateMauiApp(); } } diff --git a/src/Compatibility/ControlGallery/src/WinUI/WinUIStartup.cs b/src/Compatibility/ControlGallery/src/WinUI/WinUIStartup.cs index 43363fc9a5c1..6cf2007c0093 100644 --- a/src/Compatibility/ControlGallery/src/WinUI/WinUIStartup.cs +++ b/src/Compatibility/ControlGallery/src/WinUI/WinUIStartup.cs @@ -18,7 +18,7 @@ namespace Microsoft.Maui.Controls.Compatibility.ControlGallery.WinUI { public class WinUIMauiProgram { - public static MauiAppBuilder CreateAppBuilder() + public static MauiApp CreateMauiApp() { var builder = MauiProgram.CreateAppBuilder(); @@ -34,7 +34,7 @@ public static MauiAppBuilder CreateAppBuilder() }) .OnActivated(WinUIPageStartup.OnActivated))); - return builder; + return builder.Build(); } } diff --git a/src/Compatibility/ControlGallery/src/iOS/AppDelegate.cs b/src/Compatibility/ControlGallery/src/iOS/AppDelegate.cs index 2baef0c1ee73..8504dc256440 100644 --- a/src/Compatibility/ControlGallery/src/iOS/AppDelegate.cs +++ b/src/Compatibility/ControlGallery/src/iOS/AppDelegate.cs @@ -103,7 +103,7 @@ public string GetTestCloudDevice() [Register("AppDelegate")] public partial class AppDelegate : MauiUIApplicationDelegate { - protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); public override bool FinishedLaunching(UIApplication uiApplication, NSDictionary launchOptions) { diff --git a/src/Controls/samples/Controls.Sample.Droid/MainApplication.cs b/src/Controls/samples/Controls.Sample.Droid/MainApplication.cs index 2ac701a4a9e8..90ebd5fddfa2 100644 --- a/src/Controls/samples/Controls.Sample.Droid/MainApplication.cs +++ b/src/Controls/samples/Controls.Sample.Droid/MainApplication.cs @@ -13,6 +13,6 @@ public MainApplication(IntPtr handle, JniHandleOwnership ownership) : base(handl { } - protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } } diff --git a/src/Controls/samples/Controls.Sample.MacCatalyst/AppDelegate.cs b/src/Controls/samples/Controls.Sample.MacCatalyst/AppDelegate.cs index 96045c90f915..4069dfbf008c 100644 --- a/src/Controls/samples/Controls.Sample.MacCatalyst/AppDelegate.cs +++ b/src/Controls/samples/Controls.Sample.MacCatalyst/AppDelegate.cs @@ -13,6 +13,6 @@ namespace Sample.MacCatalyst [Register("AppDelegate")] public class AppDelegate : MauiUIApplicationDelegate { - protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } } \ No newline at end of file diff --git a/src/Controls/samples/Controls.Sample.Profiling/Platforms/Android/MainApplication.cs b/src/Controls/samples/Controls.Sample.Profiling/Platforms/Android/MainApplication.cs index ae655e667eac..ca74a7817308 100644 --- a/src/Controls/samples/Controls.Sample.Profiling/Platforms/Android/MainApplication.cs +++ b/src/Controls/samples/Controls.Sample.Profiling/Platforms/Android/MainApplication.cs @@ -12,6 +12,6 @@ public MainApplication(IntPtr handle, JniHandleOwnership ownership) : base(handl { } - protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } } \ No newline at end of file diff --git a/src/Controls/samples/Controls.Sample.Profiling/Platforms/MacCatalyst/AppDelegate.cs b/src/Controls/samples/Controls.Sample.Profiling/Platforms/MacCatalyst/AppDelegate.cs index e2f60bc805ca..067a47afe8d8 100644 --- a/src/Controls/samples/Controls.Sample.Profiling/Platforms/MacCatalyst/AppDelegate.cs +++ b/src/Controls/samples/Controls.Sample.Profiling/Platforms/MacCatalyst/AppDelegate.cs @@ -6,6 +6,6 @@ namespace Maui.Controls.Sample.Profiling [Register("AppDelegate")] public class AppDelegate : MauiUIApplicationDelegate { - protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } } \ No newline at end of file diff --git a/src/Controls/samples/Controls.Sample.Profiling/Platforms/iOS/AppDelegate.cs b/src/Controls/samples/Controls.Sample.Profiling/Platforms/iOS/AppDelegate.cs index e2f60bc805ca..067a47afe8d8 100644 --- a/src/Controls/samples/Controls.Sample.Profiling/Platforms/iOS/AppDelegate.cs +++ b/src/Controls/samples/Controls.Sample.Profiling/Platforms/iOS/AppDelegate.cs @@ -6,6 +6,6 @@ namespace Maui.Controls.Sample.Profiling [Register("AppDelegate")] public class AppDelegate : MauiUIApplicationDelegate { - protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } } \ No newline at end of file diff --git a/src/Controls/samples/Controls.Sample.Profiling/Startup.cs b/src/Controls/samples/Controls.Sample.Profiling/Startup.cs index 80be80551fc6..29f31a0acefe 100644 --- a/src/Controls/samples/Controls.Sample.Profiling/Startup.cs +++ b/src/Controls/samples/Controls.Sample.Profiling/Startup.cs @@ -9,7 +9,7 @@ namespace Maui.Controls.Sample.Profiling { public static class MauiProgram { - public static MauiAppBuilder CreateAppBuilder() + public static MauiApp CreateMauiApp() { var appBuilder = MauiApp.CreateBuilder(); @@ -20,7 +20,7 @@ public static MauiAppBuilder CreateAppBuilder() fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); }); - return appBuilder; + return builder.Build(); } } } diff --git a/src/Controls/samples/Controls.Sample.SingleProject/Platforms/Android/MainApplication.cs b/src/Controls/samples/Controls.Sample.SingleProject/Platforms/Android/MainApplication.cs index df51bc5a6fda..c51e98435125 100644 --- a/src/Controls/samples/Controls.Sample.SingleProject/Platforms/Android/MainApplication.cs +++ b/src/Controls/samples/Controls.Sample.SingleProject/Platforms/Android/MainApplication.cs @@ -12,6 +12,6 @@ public MainApplication(IntPtr handle, JniHandleOwnership ownership) : base(handl { } - protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } } \ No newline at end of file diff --git a/src/Controls/samples/Controls.Sample.SingleProject/Platforms/MacCatalyst/AppDelegate.cs b/src/Controls/samples/Controls.Sample.SingleProject/Platforms/MacCatalyst/AppDelegate.cs index 793221ce315d..f27e234b7104 100644 --- a/src/Controls/samples/Controls.Sample.SingleProject/Platforms/MacCatalyst/AppDelegate.cs +++ b/src/Controls/samples/Controls.Sample.SingleProject/Platforms/MacCatalyst/AppDelegate.cs @@ -6,6 +6,6 @@ namespace Maui.Controls.Sample.SingleProject [Register("AppDelegate")] public class AppDelegate : MauiUIApplicationDelegate { - protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } } \ No newline at end of file diff --git a/src/Controls/samples/Controls.Sample.SingleProject/Platforms/Windows/App.xaml.cs b/src/Controls/samples/Controls.Sample.SingleProject/Platforms/Windows/App.xaml.cs index 8c044d05cabf..e5c785008aa6 100644 --- a/src/Controls/samples/Controls.Sample.SingleProject/Platforms/Windows/App.xaml.cs +++ b/src/Controls/samples/Controls.Sample.SingleProject/Platforms/Windows/App.xaml.cs @@ -24,6 +24,6 @@ public App() public class MiddleApp : MauiWinUIApplication { - protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } } diff --git a/src/Controls/samples/Controls.Sample.SingleProject/Platforms/iOS/AppDelegate.cs b/src/Controls/samples/Controls.Sample.SingleProject/Platforms/iOS/AppDelegate.cs index 793221ce315d..f27e234b7104 100644 --- a/src/Controls/samples/Controls.Sample.SingleProject/Platforms/iOS/AppDelegate.cs +++ b/src/Controls/samples/Controls.Sample.SingleProject/Platforms/iOS/AppDelegate.cs @@ -6,6 +6,6 @@ namespace Maui.Controls.Sample.SingleProject [Register("AppDelegate")] public class AppDelegate : MauiUIApplicationDelegate { - protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } } \ No newline at end of file diff --git a/src/Controls/samples/Controls.Sample.SingleProject/Startup.cs b/src/Controls/samples/Controls.Sample.SingleProject/Startup.cs index 905e161a10e2..09ae9b7b3e86 100644 --- a/src/Controls/samples/Controls.Sample.SingleProject/Startup.cs +++ b/src/Controls/samples/Controls.Sample.SingleProject/Startup.cs @@ -9,7 +9,7 @@ public static class MauiProgram { internal static bool UseBlazor = false; - public static MauiAppBuilder CreateAppBuilder() + public static MauiApp CreateMauiApp() { var appBuilder = MauiApp.CreateBuilder(); appBuilder @@ -21,7 +21,7 @@ public static MauiAppBuilder CreateAppBuilder() appBuilder.Services.AddBlazorWebView(); } - return appBuilder; + return appBuilder.Build(); } } } diff --git a/src/Controls/samples/Controls.Sample.WinUI/App.xaml.cs b/src/Controls/samples/Controls.Sample.WinUI/App.xaml.cs index ab8887b1cbf9..935ad7ace227 100644 --- a/src/Controls/samples/Controls.Sample.WinUI/App.xaml.cs +++ b/src/Controls/samples/Controls.Sample.WinUI/App.xaml.cs @@ -9,6 +9,6 @@ public App() InitializeComponent(); } - protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } } \ No newline at end of file diff --git a/src/Controls/samples/Controls.Sample.iOS/AppDelegate.cs b/src/Controls/samples/Controls.Sample.iOS/AppDelegate.cs index a7f694fc4a29..b500dfdad512 100644 --- a/src/Controls/samples/Controls.Sample.iOS/AppDelegate.cs +++ b/src/Controls/samples/Controls.Sample.iOS/AppDelegate.cs @@ -6,6 +6,6 @@ namespace Maui.Controls.Sample.iOS [Register("AppDelegate")] public class AppDelegate : MauiUIApplicationDelegate { - protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } } \ No newline at end of file diff --git a/src/Controls/samples/Controls.Sample/Startup.cs b/src/Controls/samples/Controls.Sample/Startup.cs index 02f4a68ce0e8..11e183e8d03b 100644 --- a/src/Controls/samples/Controls.Sample/Startup.cs +++ b/src/Controls/samples/Controls.Sample/Startup.cs @@ -29,7 +29,7 @@ public static class MauiProgram enum PageType { Main, Blazor, Shell, Template } readonly static PageType _pageType = PageType.Main; - public static MauiAppBuilder CreateAppBuilder() + public static MauiApp CreateMauiApp() { var appBuilder = MauiApp.CreateBuilder(); @@ -213,7 +213,7 @@ static bool LogEvent(string eventName, string type = null) } }); - return appBuilder; + return appBuilder.Build(); } } } \ No newline at end of file diff --git a/src/Core/src/Platform/Android/MauiApplication.cs b/src/Core/src/Platform/Android/MauiApplication.cs index 1b184c9b949f..8212cdf38012 100644 --- a/src/Core/src/Platform/Android/MauiApplication.cs +++ b/src/Core/src/Platform/Android/MauiApplication.cs @@ -18,13 +18,13 @@ protected MauiApplication(IntPtr handle, JniHandleOwnership ownership) : base(ha Current = this; } - protected abstract MauiAppBuilder CreateAppBuilder(); + protected abstract MauiApp CreateMauiApp(); public override void OnCreate() { RegisterActivityLifecycleCallbacks(new ActivityLifecycleCallbacks()); - var builder = CreateAppBuilder(); + var mauiApp = CreateMauiApp(); //var startup = OnCreateStartup(); @@ -34,8 +34,6 @@ public override void OnCreate() // .ConfigureUsing(startup) // .Build(); - var mauiApp = builder.Build(); - Services = mauiApp.Services; Current.Services?.InvokeLifecycleEvents(del => del(this)); diff --git a/src/Core/src/Platform/Windows/MauiWinUIApplication.cs b/src/Core/src/Platform/Windows/MauiWinUIApplication.cs index 124479b4d4ce..2a42dbd96063 100644 --- a/src/Core/src/Platform/Windows/MauiWinUIApplication.cs +++ b/src/Core/src/Platform/Windows/MauiWinUIApplication.cs @@ -8,14 +8,13 @@ namespace Microsoft.Maui { public abstract class MauiWinUIApplication : UI.Xaml.Application { - protected abstract MauiAppBuilder CreateAppBuilder(); + protected abstract MauiApp CreateMauiApp(); protected override void OnLaunched(UI.Xaml.LaunchActivatedEventArgs args) { LaunchActivatedEventArgs = args; - var builder = CreateAppBuilder(); - var mauiApp = builder.Build(); + var mauiApp = CreateMauiApp(); //var startup = OnCreateStartup() ?? // throw new InvalidOperationException($"A valid startup object must be provided by overriding {nameof(OnCreateStartup)}."); diff --git a/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs b/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs index 17393005e42c..4b3612c4e018 100644 --- a/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs +++ b/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs @@ -26,11 +26,11 @@ protected MauiUIApplicationDelegate() Current = this; } - protected abstract MauiAppBuilder CreateAppBuilder(); + protected abstract MauiApp CreateMauiApp(); public override bool WillFinishLaunching(UIApplication application, NSDictionary launchOptions) { - var builder = CreateAppBuilder(); + var mauiApp = CreateMauiApp(); //var startup = OnCreateStartup(); @@ -40,8 +40,6 @@ public override bool WillFinishLaunching(UIApplication application, NSDictionary // .ConfigureUsing(startup) // .Build(); - var mauiApp = builder.Build(); - Services = mauiApp.Services; Current.Services?.InvokeLifecycleEvents(del => del(application, launchOptions)); diff --git a/src/Core/tests/DeviceTests/Platforms/Windows/App.xaml.cs b/src/Core/tests/DeviceTests/Platforms/Windows/App.xaml.cs index 502fb7c5d058..6807c71988d0 100644 --- a/src/Core/tests/DeviceTests/Platforms/Windows/App.xaml.cs +++ b/src/Core/tests/DeviceTests/Platforms/Windows/App.xaml.cs @@ -24,6 +24,6 @@ public App() public class MiddleApp : MauiWinUIApplication { - protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } } diff --git a/src/Core/tests/DeviceTests/Startup.cs b/src/Core/tests/DeviceTests/Startup.cs index 774427cb7b69..02a92e83a064 100644 --- a/src/Core/tests/DeviceTests/Startup.cs +++ b/src/Core/tests/DeviceTests/Startup.cs @@ -6,7 +6,7 @@ namespace Microsoft.Maui.DeviceTests { public static class MauiProgram { - public static MauiAppBuilder CreateAppBuilder() + public static MauiApp CreateMauiApp() { var appBuilder = MauiApp.CreateBuilder(); appBuilder @@ -32,7 +32,7 @@ public static MauiAppBuilder CreateAppBuilder() }) .UseVisualRunner(); - return appBuilder; + return appBuilder.Build(); } } } \ No newline at end of file diff --git a/src/Essentials/samples/Samples/Platforms/Android/MainApplication.cs b/src/Essentials/samples/Samples/Platforms/Android/MainApplication.cs index 53a54700bb88..538d339fce55 100644 --- a/src/Essentials/samples/Samples/Platforms/Android/MainApplication.cs +++ b/src/Essentials/samples/Samples/Platforms/Android/MainApplication.cs @@ -13,6 +13,6 @@ public MainApplication(IntPtr handle, JniHandleOwnership ownership) : base(handl { } - protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } } \ No newline at end of file diff --git a/src/Essentials/samples/Samples/Platforms/MacCatalyst/AppDelegate.cs b/src/Essentials/samples/Samples/Platforms/MacCatalyst/AppDelegate.cs index c1c1d351aae1..5ecef7672f03 100644 --- a/src/Essentials/samples/Samples/Platforms/MacCatalyst/AppDelegate.cs +++ b/src/Essentials/samples/Samples/Platforms/MacCatalyst/AppDelegate.cs @@ -6,6 +6,6 @@ namespace Samples.iOS [Register(nameof(AppDelegate))] public partial class AppDelegate : MauiUIApplicationDelegate { - protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } } \ No newline at end of file diff --git a/src/Essentials/samples/Samples/Platforms/Windows/App.xaml.cs b/src/Essentials/samples/Samples/Platforms/Windows/App.xaml.cs index 01ae020c3eeb..d1af1c35fbec 100644 --- a/src/Essentials/samples/Samples/Platforms/Windows/App.xaml.cs +++ b/src/Essentials/samples/Samples/Platforms/Windows/App.xaml.cs @@ -4,7 +4,7 @@ namespace Samples.UWP { public class MiddleApp : MauiWinUIApplication { - protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } public partial class App : MiddleApp diff --git a/src/Essentials/samples/Samples/Platforms/iOS/AppDelegate.cs b/src/Essentials/samples/Samples/Platforms/iOS/AppDelegate.cs index c1c1d351aae1..5ecef7672f03 100644 --- a/src/Essentials/samples/Samples/Platforms/iOS/AppDelegate.cs +++ b/src/Essentials/samples/Samples/Platforms/iOS/AppDelegate.cs @@ -6,6 +6,6 @@ namespace Samples.iOS [Register(nameof(AppDelegate))] public partial class AppDelegate : MauiUIApplicationDelegate { - protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } } \ No newline at end of file diff --git a/src/Essentials/samples/Samples/Startup.cs b/src/Essentials/samples/Samples/Startup.cs index fa138100c4e3..4b2cddbfa14c 100644 --- a/src/Essentials/samples/Samples/Startup.cs +++ b/src/Essentials/samples/Samples/Startup.cs @@ -6,7 +6,7 @@ namespace Samples { public static class MauiProgram { - public static MauiAppBuilder CreateAppBuilder() + public static MauiApp CreateMauiApp() { var appBuilder = MauiApp.CreateBuilder(); @@ -36,7 +36,7 @@ public static MauiAppBuilder CreateAppBuilder() }) .UseMauiApp(); - return appBuilder; + return appBuilder.Build(); } } } diff --git a/src/Essentials/test/DeviceTests/Platforms/Windows/App.xaml.cs b/src/Essentials/test/DeviceTests/Platforms/Windows/App.xaml.cs index 6200a12bb0e6..e709b6f7b89d 100644 --- a/src/Essentials/test/DeviceTests/Platforms/Windows/App.xaml.cs +++ b/src/Essentials/test/DeviceTests/Platforms/Windows/App.xaml.cs @@ -24,6 +24,6 @@ public App() public class MiddleApp : MauiWinUIApplication { - protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } } diff --git a/src/Essentials/test/DeviceTests/Startup.cs b/src/Essentials/test/DeviceTests/Startup.cs index 67bcd5e510bc..77a85b2f41ec 100644 --- a/src/Essentials/test/DeviceTests/Startup.cs +++ b/src/Essentials/test/DeviceTests/Startup.cs @@ -7,7 +7,7 @@ namespace Microsoft.Maui.Essentials.DeviceTests { public static class MauiProgram { - public static MauiAppBuilder CreateAppBuilder() + public static MauiApp CreateMauiApp() { var appBuilder = MauiApp.CreateBuilder(); appBuilder @@ -42,7 +42,7 @@ public static MauiAppBuilder CreateAppBuilder() }) .UseVisualRunner(); - return appBuilder; + return appBuilder.Build(); } } } \ No newline at end of file diff --git a/src/TestUtils/samples/DeviceTests.Sample/Platforms/Windows/App.xaml.cs b/src/TestUtils/samples/DeviceTests.Sample/Platforms/Windows/App.xaml.cs index c48b0b8f25d4..f2bb99e8fde2 100644 --- a/src/TestUtils/samples/DeviceTests.Sample/Platforms/Windows/App.xaml.cs +++ b/src/TestUtils/samples/DeviceTests.Sample/Platforms/Windows/App.xaml.cs @@ -24,6 +24,6 @@ public App() public class MiddleApp : MauiWinUIApplication { - protected override MauiAppBuilder CreateAppBuilder() => MauiProgram.CreateAppBuilder(); + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } } diff --git a/src/TestUtils/samples/DeviceTests.Sample/Startup.cs b/src/TestUtils/samples/DeviceTests.Sample/Startup.cs index 5790ba15e859..b14c923fa28c 100644 --- a/src/TestUtils/samples/DeviceTests.Sample/Startup.cs +++ b/src/TestUtils/samples/DeviceTests.Sample/Startup.cs @@ -4,7 +4,7 @@ namespace Microsoft.Maui.TestUtils.DeviceTests.Sample { public static class MauiProgram { - public static MauiAppBuilder CreateAppBuilder() + public static MauiApp CreateMauiApp() { var appBuilder = MauiApp.CreateBuilder(); appBuilder @@ -21,7 +21,7 @@ public static MauiAppBuilder CreateAppBuilder() }) .UseVisualRunner(); - return appBuilder; + return appBuilder.Build(); } } } \ No newline at end of file diff --git a/src/TestUtils/src/DeviceTests.Runners.SourceGen/RunnerGenerator.cs b/src/TestUtils/src/DeviceTests.Runners.SourceGen/RunnerGenerator.cs index e86aeca95f92..0d046d7e27d7 100644 --- a/src/TestUtils/src/DeviceTests.Runners.SourceGen/RunnerGenerator.cs +++ b/src/TestUtils/src/DeviceTests.Runners.SourceGen/RunnerGenerator.cs @@ -107,7 +107,7 @@ partial class " + appName + @" : global::Microsoft.Maui.MauiApplication { } - protected override global::Microsoft.Maui.MauiAppBuilder CreateAppBuilder() => " + mauiProgramFullName + @".CreateAppBuilder(); + protected override global::Microsoft.Maui.MauiApp CreateMauiApp() => " + mauiProgramFullName + @".CreateMauiApp(); } } #endif @@ -202,7 +202,7 @@ namespace " + RootNamespace + @" [global::Foundation.Register(""" + visualDelegateName + @""")] partial class " + visualDelegateName + @" : global::Microsoft.Maui.MauiUIApplicationDelegate { - protected override global::Microsoft.Maui.MauiAppBuilder CreateAppBuilder() => " + mauiProgramFullName + @".CreateAppBuilder(); + protected override global::Microsoft.Maui.MauiApp CreateMauiApp() => " + mauiProgramFullName + @".CreateMauiApp(); } } #endif @@ -214,7 +214,7 @@ namespace " + RootNamespace + @" partial class " + headlessDelegateName + @" : global::Microsoft.Maui.TestUtils.DeviceTests.Runners.HeadlessRunner.MauiTestApplicationDelegate { - protected override global::Microsoft.Maui.MauiAppBuilder CreateAppBuilder() => " + mauiProgramFullName + @".CreateAppBuilder(); + protected override global::Microsoft.Maui.MauiApp CreateMauiApp() => " + mauiProgramFullName + @".CreateMauiApp(); } } #endif diff --git a/src/TestUtils/src/DeviceTests.Runners/HeadlessRunner/iOS/MauiTestApplicationDelegate.cs b/src/TestUtils/src/DeviceTests.Runners/HeadlessRunner/iOS/MauiTestApplicationDelegate.cs index e9f3249be9ac..83849f33eb93 100644 --- a/src/TestUtils/src/DeviceTests.Runners/HeadlessRunner/iOS/MauiTestApplicationDelegate.cs +++ b/src/TestUtils/src/DeviceTests.Runners/HeadlessRunner/iOS/MauiTestApplicationDelegate.cs @@ -32,12 +32,11 @@ protected MauiTestApplicationDelegate() public override UIWindow? Window { get; set; } - protected abstract MauiAppBuilder CreateAppBuilder(); + protected abstract MauiApp CreateMauiApp(); public override bool WillFinishLaunching(UIApplication application, NSDictionary launchOptions) { - var builder = CreateAppBuilder(); - var mauiApp = builder.Build(); + var mauiApp = CreateMauiApp(); Services = mauiApp.Services; Options = Services.GetRequiredService(); From 3c3fe9cfc0edeaf5a79ededfc8648eea23309489 Mon Sep 17 00:00:00 2001 From: Eilon Lipton Date: Tue, 24 Aug 2021 00:00:03 -0700 Subject: [PATCH 3/7] Remove old comments --- src/Core/src/Platform/Android/MauiApplication.cs | 13 ------------- .../src/Platform/Windows/MauiWinUIApplication.cs | 13 ------------- .../src/Platform/iOS/MauiUIApplicationDelegate.cs | 13 ------------- 3 files changed, 39 deletions(-) diff --git a/src/Core/src/Platform/Android/MauiApplication.cs b/src/Core/src/Platform/Android/MauiApplication.cs index 8212cdf38012..d62f1e313bc0 100644 --- a/src/Core/src/Platform/Android/MauiApplication.cs +++ b/src/Core/src/Platform/Android/MauiApplication.cs @@ -26,14 +26,6 @@ public override void OnCreate() var mauiApp = CreateMauiApp(); - //var startup = OnCreateStartup(); - - //var host = startup - // .CreateAppHostBuilder() - // .ConfigureServices(ConfigureNativeServices) - // .ConfigureUsing(startup) - // .Build(); - Services = mauiApp.Services; Current.Services?.InvokeLifecycleEvents(del => del(this)); @@ -66,11 +58,6 @@ public override void OnConfigurationChanged(Configuration newConfig) base.OnConfigurationChanged(newConfig); } - // Configure native services like HandlersContext, ImageSourceHandlers etc.. - void ConfigureNativeServices(HostBuilderContext ctx, IServiceCollection services) - { - } - public static MauiApplication Current { get; private set; } = null!; public IServiceProvider Services { get; protected set; } = null!; diff --git a/src/Core/src/Platform/Windows/MauiWinUIApplication.cs b/src/Core/src/Platform/Windows/MauiWinUIApplication.cs index 2a42dbd96063..41d5f4b24eea 100644 --- a/src/Core/src/Platform/Windows/MauiWinUIApplication.cs +++ b/src/Core/src/Platform/Windows/MauiWinUIApplication.cs @@ -16,15 +16,6 @@ protected override void OnLaunched(UI.Xaml.LaunchActivatedEventArgs args) var mauiApp = CreateMauiApp(); - //var startup = OnCreateStartup() ?? - // throw new InvalidOperationException($"A valid startup object must be provided by overriding {nameof(OnCreateStartup)}."); - - //var host = startup - // .CreateAppHostBuilder() - // .ConfigureServices(ConfigureNativeServices) - // .ConfigureUsing(startup) - // .Build(); - Services = mauiApp.Services; Services.InvokeLifecycleEvents(del => del(this, args)); @@ -57,10 +48,6 @@ UI.Xaml.Window CreateNativeWindow(UI.Xaml.LaunchActivatedEventArgs? args = null) return winuiWndow; } - void ConfigureNativeServices(HostBuilderContext ctx, IServiceCollection services) - { - } - public static new MauiWinUIApplication Current => (MauiWinUIApplication)UI.Xaml.Application.Current; public UI.Xaml.LaunchActivatedEventArgs LaunchActivatedEventArgs { get; protected set; } = null!; diff --git a/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs b/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs index 4b3612c4e018..d9a9e0b4a72c 100644 --- a/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs +++ b/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs @@ -32,14 +32,6 @@ public override bool WillFinishLaunching(UIApplication application, NSDictionary { var mauiApp = CreateMauiApp(); - //var startup = OnCreateStartup(); - - //var host = startup - // .CreateAppHostBuilder() - // .ConfigureServices(ConfigureNativeServices) - // .ConfigureUsing(startup) - // .Build(); - Services = mauiApp.Services; Current.Services?.InvokeLifecycleEvents(del => del(application, launchOptions)); @@ -132,11 +124,6 @@ public override void WillEnterForeground(UIApplication application) Current.Services?.InvokeLifecycleEvents(del => del(application)); } - // Configure native services like HandlersContext, ImageSourceHandlers etc.. - void ConfigureNativeServices(HostBuilderContext ctx, IServiceCollection services) - { - } - public static MauiUIApplicationDelegate Current { get; private set; } = null!; public override UIWindow? Window { get; set; } From 9807d8ac2e06b4ece807168fcab551a2a845def7 Mon Sep 17 00:00:00 2001 From: Eilon Lipton Date: Wed, 25 Aug 2021 12:49:11 -0700 Subject: [PATCH 4/7] Use proper DI APIs for registering/acquiring services --- .../Core/src/AppHostBuilderExtensions.cs | 13 +++++++------ .../BordelessEntryAppHostBuilderExtensions.cs | 4 ++-- .../Extensions/EssentialsExtensions.cs | 3 ++- .../Hosting/Effects/AppHostBuilderExtensions.cs | 8 ++++++-- src/Core/src/Core/FontsMauiAppBuilderExtensions.cs | 2 +- .../Core/ImageSourcesMauiAppBuilderExtensions.cs | 7 ++++--- src/Core/src/Core/MauiAppBuilder.cs | 2 +- .../Hosting/Animations/AppHostBuilderExtensions.cs | 9 +++++---- .../LifecycleEvents/AppHostBuilderExtensions.cs | 3 ++- src/Core/src/HotReload/AppHostBuilderExtensions.cs | 5 +++-- 10 files changed, 33 insertions(+), 23 deletions(-) diff --git a/src/Compatibility/Core/src/AppHostBuilderExtensions.cs b/src/Compatibility/Core/src/AppHostBuilderExtensions.cs index bea90becd4b1..dc0fd70967a3 100644 --- a/src/Compatibility/Core/src/AppHostBuilderExtensions.cs +++ b/src/Compatibility/Core/src/AppHostBuilderExtensions.cs @@ -1,6 +1,7 @@ #nullable enable using System; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; using Microsoft.Maui.Controls.Compatibility; using Microsoft.Maui.Controls.Shapes; @@ -45,7 +46,7 @@ public static class MauiAppBuilderExtensions public static MauiAppBuilder UseMauiApp(this MauiAppBuilder builder) where TApp : class, IApplication { - builder.Services.AddSingleton(); + builder.Services.TryAddSingleton(); builder.SetupDefaults(); return builder; } @@ -53,7 +54,7 @@ public static MauiAppBuilder UseMauiApp(this MauiAppBuilder builder) public static MauiAppBuilder UseMauiApp(this MauiAppBuilder builder, Func implementationFactory) where TApp : class, IApplication { - builder.Services.AddSingleton(implementationFactory); + builder.Services.TryAddSingleton(implementationFactory); builder.SetupDefaults(); return builder; } @@ -178,14 +179,14 @@ static MauiAppBuilder SetupDefaults(this MauiAppBuilder builder) private static MauiAppBuilder AddMauiCompat(this MauiAppBuilder builder) { #if __IOS__ || MACCATALYST - builder.Services.AddSingleton(NativeGraphicsService.Instance); + builder.Services.TryAddSingleton(NativeGraphicsService.Instance); #elif __ANDROID__ - builder.Services.AddSingleton(NativeGraphicsService.Instance); + builder.Services.TryAddSingleton(NativeGraphicsService.Instance); #elif WINDOWS - builder.Services.AddSingleton(W2DGraphicsService.Instance); + builder.Services.TryAddSingleton(W2DGraphicsService.Instance); #endif - builder.Services.AddSingleton(); + builder.Services.TryAddEnumerable(ServiceDescriptor.Transient()); return builder; } diff --git a/src/Controls/samples/Controls.Sample/Controls/BordelessEntry/BordelessEntryAppHostBuilderExtensions.cs b/src/Controls/samples/Controls.Sample/Controls/BordelessEntry/BordelessEntryAppHostBuilderExtensions.cs index cb62e90351ec..52aab9565362 100644 --- a/src/Controls/samples/Controls.Sample/Controls/BordelessEntry/BordelessEntryAppHostBuilderExtensions.cs +++ b/src/Controls/samples/Controls.Sample/Controls/BordelessEntry/BordelessEntryAppHostBuilderExtensions.cs @@ -1,8 +1,8 @@ using System; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Maui; using Microsoft.Maui.Hosting; -using static Microsoft.Maui.Essentials.EssentialsExtensions; namespace Maui.Controls.Sample.Controls { @@ -10,7 +10,7 @@ static class BordelessEntryAppHostBuilderExtensions { public static MauiAppBuilder UseBordelessEntry(this MauiAppBuilder builder, Action configureDelegate = null) { - builder.Services.AddSingleton(); + builder.Services.TryAddSingleton(); if (configureDelegate != null) { diff --git a/src/Controls/samples/Controls.Sample/Extensions/EssentialsExtensions.cs b/src/Controls/samples/Controls.Sample/Extensions/EssentialsExtensions.cs index 26b43a38dd0e..3e3586885af1 100644 --- a/src/Controls/samples/Controls.Sample/Extensions/EssentialsExtensions.cs +++ b/src/Controls/samples/Controls.Sample/Extensions/EssentialsExtensions.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Maui.Hosting; @@ -16,7 +17,7 @@ public static MauiAppBuilder ConfigureEssentials(this MauiAppBuilder builder, Ac { builder.Services.AddSingleton(new EssentialsRegistration(configureDelegate)); } - builder.Services.AddSingleton(); + builder.Services.TryAddEnumerable(ServiceDescriptor.Transient()); builder.ConfigureLifecycleEvents(life => { diff --git a/src/Controls/src/Core/Hosting/Effects/AppHostBuilderExtensions.cs b/src/Controls/src/Core/Hosting/Effects/AppHostBuilderExtensions.cs index 5c12e60cc505..60cd9d84303c 100644 --- a/src/Controls/src/Core/Hosting/Effects/AppHostBuilderExtensions.cs +++ b/src/Controls/src/Core/Hosting/Effects/AppHostBuilderExtensions.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Maui.Controls.Internals; using Microsoft.Maui.Controls.Platform; @@ -10,8 +11,11 @@ public static partial class AppHostBuilderExtensions { public static MauiAppBuilder ConfigureEffects(this MauiAppBuilder builder, Action configureDelegate) { - builder.Services.AddSingleton(); - builder.Services.AddSingleton(new EffectsRegistration(configureDelegate)); + builder.Services.TryAddSingleton(); + if (configureDelegate != null) + { + builder.Services.AddSingleton(new EffectsRegistration(configureDelegate)); + } return builder; } diff --git a/src/Core/src/Core/FontsMauiAppBuilderExtensions.cs b/src/Core/src/Core/FontsMauiAppBuilderExtensions.cs index 45cafbe10868..3231505d293e 100644 --- a/src/Core/src/Core/FontsMauiAppBuilderExtensions.cs +++ b/src/Core/src/Core/FontsMauiAppBuilderExtensions.cs @@ -24,7 +24,7 @@ public static MauiAppBuilder ConfigureFonts(this MauiAppBuilder builder, Action< { builder.Services.AddSingleton(new FontsRegistration(configureDelegate)); } - builder.Services.AddSingleton(); + builder.Services.TryAddEnumerable(ServiceDescriptor.Transient()); return builder; } diff --git a/src/Core/src/Core/ImageSourcesMauiAppBuilderExtensions.cs b/src/Core/src/Core/ImageSourcesMauiAppBuilderExtensions.cs index af321e24dac4..c9e2dfacc4bd 100644 --- a/src/Core/src/Core/ImageSourcesMauiAppBuilderExtensions.cs +++ b/src/Core/src/Core/ImageSourcesMauiAppBuilderExtensions.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Maui.Hosting; using Microsoft.Maui.Hosting.Internal; @@ -27,9 +28,9 @@ public static MauiAppBuilder ConfigureImageSources(this MauiAppBuilder builder, builder.Services.AddSingleton(new ImageSourceRegistration(configureDelegate)); } - builder.Services.AddSingleton(); - builder.Services.AddSingleton(svcs => new ImageSourceServiceProvider(svcs.GetRequiredService(), svcs)); - builder.Services.AddSingleton(); + builder.Services.TryAddSingleton(); + builder.Services.TryAddSingleton(svcs => new ImageSourceServiceProvider(svcs.GetRequiredService(), svcs)); + builder.Services.TryAddSingleton(); return builder; } diff --git a/src/Core/src/Core/MauiAppBuilder.cs b/src/Core/src/Core/MauiAppBuilder.cs index 54a0e8ee6fcd..095fc9b7bfcc 100644 --- a/src/Core/src/Core/MauiAppBuilder.cs +++ b/src/Core/src/Core/MauiAppBuilder.cs @@ -141,7 +141,7 @@ public MauiApp Build() _services.IsReadOnly = true; - var initServices = _builtApplication.Services.GetService>(); + var initServices = _builtApplication.Services.GetServices(); if (initServices != null) { foreach (var instance in initServices) diff --git a/src/Core/src/Hosting/Animations/AppHostBuilderExtensions.cs b/src/Core/src/Hosting/Animations/AppHostBuilderExtensions.cs index c96f2c129bce..4c4bf5eb971b 100644 --- a/src/Core/src/Hosting/Animations/AppHostBuilderExtensions.cs +++ b/src/Core/src/Hosting/Animations/AppHostBuilderExtensions.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Maui.Animations; #if __ANDROID__ using Microsoft.Maui.Platform; @@ -11,12 +12,12 @@ public static partial class AppHostBuilderExtensions public static MauiAppBuilder ConfigureAnimations(this MauiAppBuilder builder) { #if __ANDROID__ - builder.Services.AddSingleton(svcs => new EnergySaverListenerManager()); - builder.Services.AddTransient(svcs => new NativeTicker(svcs.GetRequiredService())); + builder.Services.TryAddSingleton(svcs => new EnergySaverListenerManager()); + builder.Services.TryAddTransient(svcs => new NativeTicker(svcs.GetRequiredService())); #else - builder.Services.AddTransient(svcs => new NativeTicker()); + builder.Services.TryAddTransient(svcs => new NativeTicker()); #endif - builder.Services.AddTransient(svcs => new AnimationManager(svcs.GetRequiredService())); + builder.Services.TryAddTransient(svcs => new AnimationManager(svcs.GetRequiredService())); return builder; } diff --git a/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.cs b/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.cs index 9fd22b800716..4c08da0e3656 100644 --- a/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.cs +++ b/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.cs @@ -1,5 +1,6 @@ using System; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; namespace Microsoft.Maui.LifecycleEvents { @@ -22,7 +23,7 @@ public static partial class MauiAppHostBuilderExtensions { public static MauiAppBuilder ConfigureLifecycleEvents(this MauiAppBuilder builder, Action? configureDelegate) { - builder.Services.AddSingleton(); + builder.Services.TryAddSingleton(); if (configureDelegate != null) { builder.Services.AddSingleton(new LifecycleEventRegistration(configureDelegate)); diff --git a/src/Core/src/HotReload/AppHostBuilderExtensions.cs b/src/Core/src/HotReload/AppHostBuilderExtensions.cs index 745f0b5ceaa1..b2e6e351e264 100644 --- a/src/Core/src/HotReload/AppHostBuilderExtensions.cs +++ b/src/Core/src/HotReload/AppHostBuilderExtensions.cs @@ -2,6 +2,7 @@ using System; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; using Microsoft.Maui.HotReload; @@ -11,11 +12,11 @@ public static partial class AppHostBuilderExtensions { public static MauiAppBuilder EnableHotReload(this MauiAppBuilder builder, string? ideIp = null, int idePort = 9988) { - builder.Services.AddSingleton(new HotReloadBuilder + builder.Services.TryAddEnumerable(ServiceDescriptor.Transient(_ => new HotReloadBuilder { IdeIp = ideIp, IdePort = idePort, - }); + })); return builder; } From f4f1066ec659c80e64448e287a322ec68528b40c Mon Sep 17 00:00:00 2001 From: Eilon Lipton Date: Wed, 25 Aug 2021 13:19:25 -0700 Subject: [PATCH 5/7] Update project templates to use new pattern --- .../MauiApp1/{Startup.cs => MauiProgram.cs} | 18 +++++++++--------- .../Platforms/Android/MainApplication.cs | 4 +++- .../Platforms/MacCatalyst/AppDelegate.cs | 3 ++- .../MauiApp1/Platforms/Windows/App.xaml.cs | 2 +- .../MauiApp1/Platforms/iOS/AppDelegate.cs | 3 ++- .../MauiApp1/{Startup.cs => MauiProgram.cs} | 9 ++++++--- .../Platforms/Android/MainApplication.cs | 4 +++- .../Platforms/MacCatalyst/AppDelegate.cs | 3 ++- .../MauiApp1/Platforms/Windows/App.xaml.cs | 2 +- .../MauiApp1/Platforms/iOS/AppDelegate.cs | 3 ++- 10 files changed, 31 insertions(+), 20 deletions(-) rename src/Templates/src/templates/maui-blazor/MauiApp1/{Startup.cs => MauiProgram.cs} (66%) rename src/Templates/src/templates/maui-mobile/MauiApp1/{Startup.cs => MauiProgram.cs} (72%) diff --git a/src/Templates/src/templates/maui-blazor/MauiApp1/Startup.cs b/src/Templates/src/templates/maui-blazor/MauiApp1/MauiProgram.cs similarity index 66% rename from src/Templates/src/templates/maui-blazor/MauiApp1/Startup.cs rename to src/Templates/src/templates/maui-blazor/MauiApp1/MauiProgram.cs index 61a369c43867..c9008939af35 100644 --- a/src/Templates/src/templates/maui-blazor/MauiApp1/Startup.cs +++ b/src/Templates/src/templates/maui-blazor/MauiApp1/MauiProgram.cs @@ -11,23 +11,23 @@ namespace MauiApp1 { - public class Startup : IStartup + public static class MauiProgram { - public void Configure(IAppHostBuilder appBuilder) + public static MauiApp CreateMauiApp() { - appBuilder + var builder = MauiApp.CreateBuilder(); + builder .RegisterBlazorMauiWebView() - .UseMicrosoftExtensionsServiceProviderFactory() .UseMauiApp() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); - }) - .ConfigureServices(services => - { - services.AddBlazorWebView(); - services.AddSingleton(); }); + + builder.Services.AddBlazorWebView(); + builder.Services.AddSingleton(); + + return builder.Build(); } } } \ No newline at end of file diff --git a/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Android/MainApplication.cs b/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Android/MainApplication.cs index 3c15169c57be..1fd323907a07 100644 --- a/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Android/MainApplication.cs +++ b/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Android/MainApplication.cs @@ -6,11 +6,13 @@ namespace MauiApp1 { [Application] - public class MainApplication : MauiApplication + public class MainApplication : MauiApplication { public MainApplication(IntPtr handle, JniHandleOwnership ownership) : base(handle, ownership) { } + + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } } \ No newline at end of file diff --git a/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/MacCatalyst/AppDelegate.cs b/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/MacCatalyst/AppDelegate.cs index 346c91335b0b..8babe50ba38f 100644 --- a/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/MacCatalyst/AppDelegate.cs +++ b/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/MacCatalyst/AppDelegate.cs @@ -4,7 +4,8 @@ namespace MauiApp1 { [Register("AppDelegate")] - public class AppDelegate : MauiUIApplicationDelegate + public class AppDelegate : MauiUIApplicationDelegate { + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } } \ No newline at end of file diff --git a/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Windows/App.xaml.cs b/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Windows/App.xaml.cs index b7124be7b613..e4188ad7be9e 100644 --- a/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Windows/App.xaml.cs +++ b/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Windows/App.xaml.cs @@ -21,7 +21,7 @@ public App() this.InitializeComponent(); } - protected override IStartup OnCreateStartup() => new Startup(); + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); protected override void OnLaunched(LaunchActivatedEventArgs args) { diff --git a/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/iOS/AppDelegate.cs b/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/iOS/AppDelegate.cs index 346c91335b0b..8babe50ba38f 100644 --- a/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/iOS/AppDelegate.cs +++ b/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/iOS/AppDelegate.cs @@ -4,7 +4,8 @@ namespace MauiApp1 { [Register("AppDelegate")] - public class AppDelegate : MauiUIApplicationDelegate + public class AppDelegate : MauiUIApplicationDelegate { + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } } \ No newline at end of file diff --git a/src/Templates/src/templates/maui-mobile/MauiApp1/Startup.cs b/src/Templates/src/templates/maui-mobile/MauiApp1/MauiProgram.cs similarity index 72% rename from src/Templates/src/templates/maui-mobile/MauiApp1/Startup.cs rename to src/Templates/src/templates/maui-mobile/MauiApp1/MauiProgram.cs index 21c97d6a40ba..3acde13b33e1 100644 --- a/src/Templates/src/templates/maui-mobile/MauiApp1/Startup.cs +++ b/src/Templates/src/templates/maui-mobile/MauiApp1/MauiProgram.cs @@ -8,16 +8,19 @@ namespace MauiApp1 { - public class Startup : IStartup + public static class MauiProgram { - public void Configure(IAppHostBuilder appBuilder) + public static MauiApp CreateMauiApp() { - appBuilder + var builder = MauiApp.CreateBuilder(); + builder .UseMauiApp() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); }); + + return builder.Build(); } } } \ No newline at end of file diff --git a/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Android/MainApplication.cs b/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Android/MainApplication.cs index 3c15169c57be..1fd323907a07 100644 --- a/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Android/MainApplication.cs +++ b/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Android/MainApplication.cs @@ -6,11 +6,13 @@ namespace MauiApp1 { [Application] - public class MainApplication : MauiApplication + public class MainApplication : MauiApplication { public MainApplication(IntPtr handle, JniHandleOwnership ownership) : base(handle, ownership) { } + + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } } \ No newline at end of file diff --git a/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/MacCatalyst/AppDelegate.cs b/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/MacCatalyst/AppDelegate.cs index 346c91335b0b..8babe50ba38f 100644 --- a/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/MacCatalyst/AppDelegate.cs +++ b/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/MacCatalyst/AppDelegate.cs @@ -4,7 +4,8 @@ namespace MauiApp1 { [Register("AppDelegate")] - public class AppDelegate : MauiUIApplicationDelegate + public class AppDelegate : MauiUIApplicationDelegate { + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } } \ No newline at end of file diff --git a/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Windows/App.xaml.cs b/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Windows/App.xaml.cs index b7124be7b613..e4188ad7be9e 100644 --- a/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Windows/App.xaml.cs +++ b/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Windows/App.xaml.cs @@ -21,7 +21,7 @@ public App() this.InitializeComponent(); } - protected override IStartup OnCreateStartup() => new Startup(); + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); protected override void OnLaunched(LaunchActivatedEventArgs args) { diff --git a/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/iOS/AppDelegate.cs b/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/iOS/AppDelegate.cs index 346c91335b0b..8babe50ba38f 100644 --- a/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/iOS/AppDelegate.cs +++ b/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/iOS/AppDelegate.cs @@ -4,7 +4,8 @@ namespace MauiApp1 { [Register("AppDelegate")] - public class AppDelegate : MauiUIApplicationDelegate + public class AppDelegate : MauiUIApplicationDelegate { + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } } \ No newline at end of file From e61640b5d51ad82c8d1e64deba9bf47b54282bfc Mon Sep 17 00:00:00 2001 From: Eilon Lipton Date: Wed, 25 Aug 2021 13:40:37 -0700 Subject: [PATCH 6/7] Fix build --- src/Compatibility/ControlGallery/src/WinUI/WinUIStartup.cs | 2 +- src/Controls/samples/Controls.Sample.Profiling/Startup.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Compatibility/ControlGallery/src/WinUI/WinUIStartup.cs b/src/Compatibility/ControlGallery/src/WinUI/WinUIStartup.cs index 6cf2007c0093..e27bca68c3fa 100644 --- a/src/Compatibility/ControlGallery/src/WinUI/WinUIStartup.cs +++ b/src/Compatibility/ControlGallery/src/WinUI/WinUIStartup.cs @@ -20,7 +20,7 @@ public class WinUIMauiProgram { public static MauiApp CreateMauiApp() { - var builder = MauiProgram.CreateAppBuilder(); + var builder = MauiProgram.CreateMauiAppBuilder(); builder.ConfigureLifecycleEvents(lifecycle => lifecycle .AddWindows(windows => windows diff --git a/src/Controls/samples/Controls.Sample.Profiling/Startup.cs b/src/Controls/samples/Controls.Sample.Profiling/Startup.cs index 29f31a0acefe..c309ae512252 100644 --- a/src/Controls/samples/Controls.Sample.Profiling/Startup.cs +++ b/src/Controls/samples/Controls.Sample.Profiling/Startup.cs @@ -11,9 +11,9 @@ public static class MauiProgram { public static MauiApp CreateMauiApp() { - var appBuilder = MauiApp.CreateBuilder(); + var builder = MauiApp.CreateBuilder(); - appBuilder + builder .UseMauiApp() .ConfigureFonts(fonts => { From 316d8d192047d4444611c62cc75e2e90d8ca0896 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Thu, 26 Aug 2021 05:19:49 +0200 Subject: [PATCH 7/7] Make sure we have a copy of the envvars Works around https://github.com/xamarin/xamarin-macios/issues/12555 --- .config/dotnet-tools.json | 2 +- .../iOS/MauiTestApplicationDelegate.cs | 45 +++++++++++++++++++ .../TestUtils.DeviceTests.Runners.csproj | 2 +- 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 981af17fef54..b4c179a3cd54 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -15,7 +15,7 @@ ] }, "microsoft.dotnet.xharness.cli": { - "version": "1.0.0-prerelease.21404.1", + "version": "1.0.0-prerelease.21425.2", "commands": [ "xharness" ] diff --git a/src/TestUtils/src/DeviceTests.Runners/HeadlessRunner/iOS/MauiTestApplicationDelegate.cs b/src/TestUtils/src/DeviceTests.Runners/HeadlessRunner/iOS/MauiTestApplicationDelegate.cs index 83849f33eb93..96231ebc4303 100644 --- a/src/TestUtils/src/DeviceTests.Runners/HeadlessRunner/iOS/MauiTestApplicationDelegate.cs +++ b/src/TestUtils/src/DeviceTests.Runners/HeadlessRunner/iOS/MauiTestApplicationDelegate.cs @@ -6,11 +6,54 @@ using UIKit; using Microsoft.Extensions.DependencyInjection; using Microsoft.Maui.Hosting; +using Microsoft.DotNet.XHarness.iOS.Shared.Execution; namespace Microsoft.Maui.TestUtils.DeviceTests.Runners.HeadlessRunner { public abstract class MauiTestApplicationDelegate : UIApplicationDelegate { + // TODO: https://github.com/xamarin/xamarin-macios/issues/12555 + readonly static string[] EnvVarNames = { + "NUNIT_AUTOSTART", + "NUNIT_AUTOEXIT", + "NUNIT_ENABLE_NETWORK", + "DISABLE_SYSTEM_PERMISSION_TESTS", + "NUNIT_HOSTNAME", + "NUNIT_TRANSPORT", + "NUNIT_LOG_FILE", + "NUNIT_HOSTPORT", + "USE_TCP_TUNNEL", + "RUN_END_TAG", + "NUNIT_ENABLE_XML_OUTPUT", + "NUNIT_ENABLE_XML_MODE", + "NUNIT_XML_VERSION", + "NUNIT_SORTNAMES", + "NUNIT_RUN_ALL", + "NUNIT_SKIPPED_METHODS", + "NUNIT_SKIPPED_CLASSES", + }; + + readonly static Dictionary EnvVars = new(); + + static MauiTestApplicationDelegate() + { + // copy into dictionary for later + foreach (var envvar in EnvVarNames) + { + EnvVars[envvar] = Environment.GetEnvironmentVariable(envvar); + } + } + + static void SetEnvironmentVariables() + { + // read from dictionary + foreach (var envvar in EnvVars) + { + Console.WriteLine($" {envvar.Key} = '{envvar.Value}'"); + Environment.SetEnvironmentVariable(envvar.Key, envvar.Value); + } + } + public static bool IsHeadlessRunner(string[] args) { // usually means this is from xharness @@ -39,6 +82,8 @@ public override bool WillFinishLaunching(UIApplication application, NSDictionary var mauiApp = CreateMauiApp(); Services = mauiApp.Services; + SetEnvironmentVariables(); + Options = Services.GetRequiredService(); RunnerOptions = Services.GetRequiredService(); diff --git a/src/TestUtils/src/DeviceTests.Runners/TestUtils.DeviceTests.Runners.csproj b/src/TestUtils/src/DeviceTests.Runners/TestUtils.DeviceTests.Runners.csproj index dc8e2ca21039..8f2329f16593 100644 --- a/src/TestUtils/src/DeviceTests.Runners/TestUtils.DeviceTests.Runners.csproj +++ b/src/TestUtils/src/DeviceTests.Runners/TestUtils.DeviceTests.Runners.csproj @@ -19,7 +19,7 @@ - +