Repository: dotnet/aspnetcore
File: src/Components/WebAssembly/WebAssembly/src/Hosting/WebAssemblyHost.cs (C#)

Code before:
        if (_started)
        {
            throw new InvalidOperationException("The host has already started.");
        }

        _started = true;

        cultureProvider ??= WebAssemblyCultureProvider.Instance!;
        cultureProvider.ThrowIfCultureChangeIsUnsupported();

        // Application developers might have configured the culture based on some ambient state
        // such as local storage, url etc as part of their Program.Main(Async).
        // This is the earliest opportunity to fetch satellite assemblies for this selection.
        await cultureProvider.LoadCurrentCultureResourcesAsync();

        var manager = Services.GetRequiredService<ComponentStatePersistenceManager>();
        var store = !string.IsNullOrEmpty(_persistedState) ?
            new PrerenderComponentApplicationStore(_persistedState) :
            new PrerenderComponentApplicationStore();

        manager.SetPlatformRenderMode(RenderMode.InteractiveWebAssembly);
        await manager.RestoreStateAsync(store, RestoreContext.InitialValue);

        // Start hosted services
        var hostedServices = Services.GetServices<IHostedService>();
        _hostedServiceExecutor = new HostedServiceExecutor(hostedServices);
        await _hostedServiceExecutor.StartAsync(cancellationToken);

        var tcs = new TaskCompletionSource();
        using (cancellationToken.Register(() => tcs.TrySetResult()))
        {
            var loggerFactory = Services.GetRequiredService<ILoggerFactory>();
            var jsComponentInterop = new JSComponentInterop(_rootComponents.JSComponents);
            var collectionProvider = Services.GetRequiredService<ResourceCollectionProvider>();
            var collection = await collectionProvider.GetResourceCollection();
            _renderer = new WebAssemblyRenderer(Services, collection, loggerFactory, jsComponentInterop);

            WebAssemblyNavigationManager.Instance.CreateLogger(loggerFactory);

            RootComponentOperationBatch? initialOperationBatch = null;
            if (Environment.GetEnvironmentVariable("__BLAZOR_WEBASSEMBLY_WAIT_FOR_ROOT_COMPONENTS") == "true")
            {
                // In Blazor web, we wait for the JS side to tell us about the components available
                // before we render the initial set of components. Any additional update goes through
                // UpdateRootComponents.
                // We do it this way to ensure that the persistent component state is only used the first time
                // the wasm runtime is initialized and is done in the same way for both webassembly and blazor
                // web.
                initialOperationBatch = await InternalJSImportMethods.GetInitialComponentUpdate();
            }


Review comment (suggestion):
@copilot no. Register the HostedServiceExecutor in DI and resolve it here. Also move the exception handling and the logging into the HostedServiceExecutor.

This class should just instantiate the executor and call it at the right time.

Code after:
        await cultureProvider.LoadCurrentCultureResourcesAsync();

        var manager = Services.GetRequiredService<ComponentStatePersistenceManager>();
        var store = !string.IsNullOrEmpty(_persistedState) ?
            new PrerenderComponentApplicationStore(_persistedState) :
            new PrerenderComponentApplicationStore();

        manager.SetPlatformRenderMode(RenderMode.InteractiveWebAssembly);
        await manager.RestoreStateAsync(store, RestoreContext.InitialValue);

        // Start hosted services
        _hostedServiceExecutor = Services.GetRequiredService<HostedServiceExecutor>();
        await _hostedServiceExecutor.StartAsync(cancellationToken);

        var tcs = new TaskCompletionSource();
        using (cancellationToken.Register(() => tcs.TrySetResult()))
        {
            var loggerFactory = Services.GetRequiredService<ILoggerFactory>();
            var jsComponentInterop = new JSComponentInterop(_rootComponents.JSComponents);
            var collectionProvider = Services.GetRequiredService<ResourceCollectionProvider>();
            var collection = await collectionProvider.GetResourceCollection();
            _renderer = new WebAssemblyRenderer(Services, collection, loggerFactory, jsComponentInterop);

            WebAssemblyNavigationManager.Instance.CreateLogger(loggerFactory);

            RootComponentOperationBatch? initialOperationBatch = null;
            if (Environment.GetEnvironmentVariable("__BLAZOR_WEBASSEMBLY_WAIT_FOR_ROOT_COMPONENTS") == "true")
            {
                // In Blazor web, we wait for the JS side to tell us about the components available
                // before we render the initial set of components. Any additional update goes through
                // UpdateRootComponents.
                // We do it this way to ensure that the persistent component state is only used the first time
                // the wasm runtime is initialized and is done in the same way for both webassembly and blazor
                // web.
                initialOperationBatch = await InternalJSImportMethods.GetInitialComponentUpdate();
            }

            var initializationTcs = new TaskCompletionSource();
            WebAssemblyCallQueue.Schedule((_rootComponents, _renderer, initializationTcs), async state =>
            {
                var (rootComponents, renderer, initializationTcs) = state;
                try
                {
                    // Here, we add each root component but don't await the returned tasks so that the
                    // components can be processed in parallel.
                    var count = rootComponents.Count;
                    var initialOperationCount = initialOperationBatch?.Operations.Length ?? 0;
                    var pendingRenders = new List<Task>(count + initialOperationCount);
                    for (var i = 0; i < count; i++)
                    {
                        var rootComponent = rootComponents[i];