Skip to content

Commit 8b1d70e

Browse files
chore: Rework hosting internals
1 parent 9262b7f commit 8b1d70e

16 files changed

Lines changed: 288 additions & 249 deletions

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,9 @@ It is also possible to configure these values through `appsettings.json` like so
9696
}
9797
```
9898

99-
Blazor Desktop will automatically install WebView2 for the user if they do not already have it installed, you can disable this if you wish:
99+
Blazor Desktop will automatically install a web view runtime for the user if they do not already have it installed, you can disable this if you wish:
100100
```csharp
101-
builder.Window.UseWebView2Installer(false);
101+
builder.UseWebViewInstaller(false);
102102
```
103103

104104
**The `Window` object itself is also made available inside of the DI container, so you can access all properties on it by using the inject Razor keyword or requesting it through the constructor of a class added as a service.**

src/BlazorDesktop.Sample/Program.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
using Microsoft.AspNetCore.Components.Web;
99

1010
var builder = BlazorDesktopHostBuilder.CreateDefault(args);
11+
12+
builder.UseWebViewInstaller();
13+
1114
builder.RootComponents.Add<App>("#app");
1215
builder.RootComponents.Add<HeadOutlet>("head::after");
1316

src/BlazorDesktop.Sample/Properties/launchSettings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"commandName": "Project",
55
"dotnetRunMessages": true,
66
"environmentVariables": {
7-
"DOTNET_ENVIRONMENT": "Development"
7+
"ASPNETCORE_ENVIRONMENT": "Development"
88
}
99
}
1010
}

src/BlazorDesktop.Templates/templates/BlazorDesktop-CSharp/Program.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
using Microsoft.AspNetCore.Components.Web;
55

66
var builder = BlazorDesktopHostBuilder.CreateDefault(args);
7+
8+
builder.UseWebViewInstaller();
9+
710
builder.RootComponents.Add<App>("#app");
811
builder.RootComponents.Add<HeadOutlet>("head::after");
912

src/BlazorDesktop.Templates/templates/BlazorDesktop-CSharp/Properties/launchSettings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"commandName": "Project",
55
"dotnetRunMessages": true,
66
"environmentVariables": {
7-
"DOTNET_ENVIRONMENT": "Development"
7+
"ASPNETCORE_ENVIRONMENT": "Development"
88
}
99
}
1010
}

src/BlazorDesktop/Hosting/BlazorDesktopHost.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,6 @@ namespace BlazorDesktop.Hosting;
1010
/// </summary>
1111
public sealed class BlazorDesktopHost : IHost, IAsyncDisposable
1212
{
13-
/// <summary>
14-
/// The host.
15-
/// </summary>
16-
private readonly IHost _host;
17-
1813
/// <summary>
1914
/// Gets the application configuration.
2015
/// </summary>
@@ -25,6 +20,11 @@ public sealed class BlazorDesktopHost : IHost, IAsyncDisposable
2520
/// </summary>
2621
public IServiceProvider Services => _host.Services;
2722

23+
/// <summary>
24+
/// The host.
25+
/// </summary>
26+
private readonly IHost _host;
27+
2828
/// <summary>
2929
/// Creates an instance of <see cref="BlazorDesktopHost"/> with a specified <see cref="IHost"/>.
3030
/// </summary>

src/BlazorDesktop/Hosting/BlazorDesktopHostBuilder.cs

Lines changed: 94 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,11 @@ namespace BlazorDesktop.Hosting;
1313
/// </summary>
1414
public sealed class BlazorDesktopHostBuilder
1515
{
16-
/// <summary>
17-
/// The host builder.
18-
/// </summary>
19-
private readonly IHostBuilder _hostBuilder;
20-
2116
/// <summary>
2217
/// Gets an <see cref="ConfigurationManager"/> that can be used to customize the application's
2318
/// configuration sources and read configuration attributes.
2419
/// </summary>
25-
public ConfigurationManager Configuration { get; }
20+
public ConfigurationManager Configuration => _hostApplicationBuilder.Configuration;
2621

2722
/// <summary>
2823
/// Gets the collection of root component mappings configured for the application.
@@ -32,7 +27,7 @@ public sealed class BlazorDesktopHostBuilder
3227
/// <summary>
3328
/// Gets the service collection.
3429
/// </summary>
35-
public IServiceCollection Services { get; }
30+
public IServiceCollection Services => _hostApplicationBuilder.Services;
3631

3732
/// <summary>
3833
/// Gets information about the app's host environment.
@@ -42,27 +37,31 @@ public sealed class BlazorDesktopHostBuilder
4237
/// <summary>
4338
/// Gets the logging builder for configuring logging services.
4439
/// </summary>
45-
public ILoggingBuilder Logging { get; }
40+
public ILoggingBuilder Logging => _hostApplicationBuilder.Logging;
4641

4742
/// <summary>
4843
/// Exposes configuration options for the window.
4944
/// </summary>
5045
public ConfigureWindowBuilder Window { get; }
5146

47+
/// <summary>
48+
/// The host application builder.
49+
/// </summary>
50+
private readonly HostApplicationBuilder _hostApplicationBuilder;
51+
5252
/// <summary>
5353
/// Creates an instance of <see cref="BlazorDesktopHostBuilder"/> with the minimal configuration.
5454
/// </summary>
5555
/// <param name="args">The arguments passed to the application's main method.</param>
56-
internal BlazorDesktopHostBuilder(string[]? args)
56+
private BlazorDesktopHostBuilder(string[]? args)
5757
{
58-
_hostBuilder = Host.CreateDefaultBuilder(args);
59-
60-
Configuration = new();
61-
RootComponents = new();
62-
Services = new ServiceCollection();
63-
Logging = new LoggingBuilder(Services);
64-
Window = new(Configuration);
65-
HostEnvironment = InitializeEnvironment(args);
58+
_hostApplicationBuilder = InitializeHostApplicationBuilder(args);
59+
60+
InitializeDefaultServices();
61+
62+
RootComponents = InitializeRootComponents();
63+
HostEnvironment = InitializeEnvironment();
64+
Window = InitializeWindowBuilder();
6665
}
6766

6867
/// <summary>
@@ -76,61 +75,107 @@ public static BlazorDesktopHostBuilder CreateDefault(string[]? args = default)
7675
return new(args);
7776
}
7877

78+
/// <summary>
79+
/// Registers a <see cref="IServiceProviderFactory{TBuilder}" /> instance to be used to create the <see cref="IServiceProvider" />.
80+
/// </summary>
81+
/// <typeparam name="TBuilder">The type of builder provided by the <see cref="IServiceProviderFactory{TBuilder}" />.</typeparam>
82+
/// <param name="factory">The <see cref="IServiceProviderFactory{TBuilder}" />.</param>
83+
/// <param name="configure">
84+
/// A delegate used to configure the <typeparamref T="TBuilder" />. This can be used to configure services using
85+
/// APIs specific to the <see cref="IServiceProviderFactory{TBuilder}" /> implementation.
86+
/// </param>
87+
/// <exception cref="ArgumentNullException">Occurs when the <paramref name="factory"/> parameter is null.</exception>
88+
/// <remarks>
89+
/// <para>
90+
/// <see cref="ConfigureContainer{TBuilder}(IServiceProviderFactory{TBuilder}, Action{TBuilder})"/> is called by <see cref="Build"/>
91+
/// and so the delegate provided by <paramref name="configure"/> will run after all other services have been registered.
92+
/// </para>
93+
/// <para>
94+
/// Multiple calls to <see cref="ConfigureContainer{TBuilder}(IServiceProviderFactory{TBuilder}, Action{TBuilder})"/> will replace
95+
/// the previously stored <paramref name="factory"/> and <paramref name="configure"/> delegate.
96+
/// </para>
97+
/// </remarks>
98+
public void ConfigureContainer<TBuilder>(IServiceProviderFactory<TBuilder> factory, Action<TBuilder>? configure = null) where TBuilder : notnull
99+
{
100+
if (factory == null)
101+
{
102+
throw new ArgumentNullException(nameof(factory));
103+
}
104+
105+
_hostApplicationBuilder.ConfigureContainer(factory, configure);
106+
}
107+
79108
/// <summary>
80109
/// Builds a <see cref="BlazorDesktopHost"/> instance based on the configuration of this builder.
81110
/// </summary>
82111
/// <returns>A <see cref="BlazorDesktopHost"/> object.</returns>
83112
public BlazorDesktopHost Build()
84113
{
85-
((BlazorDesktopHostingEnvironment)HostEnvironment).SaveConfig(Configuration);
86-
87-
var builder = _hostBuilder.ConfigureAppConfiguration(builder =>
88-
{
89-
builder.AddConfiguration(Configuration);
90-
})
91-
.ConfigureServices(services =>
92-
{
93-
services.AddWpfBlazorWebView();
114+
return new(_hostApplicationBuilder.Build());
115+
}
94116

95-
services.AddSingleton(HostEnvironment);
96-
services.AddSingleton(RootComponents);
97-
services.AddSingleton<Window, BlazorDesktopWindow>();
98-
services.AddSingleton<Application>();
117+
/// <summary>
118+
/// Initializes the host application builder.
119+
/// </summary>
120+
/// <param name="args">The arguments passed to the application's main method.</param>
121+
/// <returns>A <see cref="HostApplicationBuilder"/>.</returns>
122+
private static HostApplicationBuilder InitializeHostApplicationBuilder(string[]? args)
123+
{
124+
var configuration = new ConfigurationManager();
99125

100-
services.AddHostedService<BlazorDesktopService>();
126+
configuration.AddEnvironmentVariables("ASPNETCORE_");
101127

102-
foreach (var service in Services)
103-
{
104-
services.Add(service);
105-
}
128+
return new(new HostApplicationBuilderSettings
129+
{
130+
Args = args,
131+
Configuration = configuration
106132
});
133+
}
107134

108-
return new(builder.Build());
135+
/// <summary>
136+
/// Initializes the default services.
137+
/// </summary>
138+
private void InitializeDefaultServices()
139+
{
140+
Services.AddWpfBlazorWebView();
141+
Services.AddSingleton<WebViewInstaller>();
142+
Services.AddSingleton<Application>();
143+
Services.AddSingleton<Window, BlazorDesktopWindow>();
144+
Services.AddHostedService<BlazorDesktopService>();
109145
}
110146

111147
/// <summary>
112-
/// Adds Chromium dev tools to the Blazor Desktop application.
148+
/// Initializes the root components.
113149
/// </summary>
114-
/// <returns>The <see cref="BlazorDesktopHostBuilder"/>.</returns>
115-
public BlazorDesktopHostBuilder UseDeveloperTools()
150+
/// <returns>A <see cref="RootComponentMappingCollection"/>.</returns>
151+
private RootComponentMappingCollection InitializeRootComponents()
116152
{
117-
Services.AddBlazorWebViewDeveloperTools();
118-
return this;
153+
var rootComponents = new RootComponentMappingCollection();
154+
155+
Services.AddSingleton(rootComponents);
156+
157+
return rootComponents;
119158
}
120159

121160
/// <summary>
122161
/// Initializes the environment.
123162
/// </summary>
124-
/// <param name="args">The arguments passed to the application's main method.</param>
125-
/// <returns>A <see cref="BlazorDesktopHostingEnvironment"/>.</returns>
126-
private static BlazorDesktopHostingEnvironment InitializeEnvironment(string[]? args)
163+
/// <returns>A <see cref="BlazorDesktopHostEnvironment"/>.</returns>
164+
private BlazorDesktopHostEnvironment InitializeEnvironment()
127165
{
128-
var environmentHost = Host.CreateDefaultBuilder(args).Build();
129-
var environment = new BlazorDesktopHostingEnvironment();
130-
var config = environmentHost.Services.GetRequiredService<IConfiguration>();
166+
var hostEnvironment = new BlazorDesktopHostEnvironment(_hostApplicationBuilder.Environment, Configuration);
131167

132-
environment.LoadConfig(config);
168+
Services.AddSingleton<IWebHostEnvironment>(hostEnvironment);
133169

134-
return environment;
170+
return hostEnvironment;
171+
}
172+
173+
/// <summary>
174+
/// Initializes the window builder.
175+
/// </summary>
176+
/// <returns>A <see cref="ConfigureWindowBuilder"/>.</returns>
177+
private ConfigureWindowBuilder InitializeWindowBuilder()
178+
{
179+
return new ConfigureWindowBuilder(Configuration);
135180
}
136181
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Licensed to the Blazor Desktop Contributors under one or more agreements.
2+
// The Blazor Desktop Contributors licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using BlazorDesktop.Wpf;
6+
7+
namespace BlazorDesktop.Hosting;
8+
9+
/// <summary>
10+
/// Extension methods for configuring the <see cref="BlazorDesktopHostBuilder" />.
11+
/// </summary>
12+
public static class BlazorDesktopHostBuilderExtensions
13+
{
14+
/// <summary>
15+
/// Installs a web view on the machine.
16+
/// </summary>
17+
/// <param name="builder">The <see cref="BlazorDesktopHostBuilder"/>.</param>
18+
/// <param name="useInstaller">If the installer should be used.</param>
19+
/// <param name="silentInstall">If the installer should be silent.</param>
20+
/// <returns>A reference to the <paramref name="builder"/> after the operation has completed.</returns>
21+
public static BlazorDesktopHostBuilder UseWebViewInstaller(this BlazorDesktopHostBuilder builder, bool useInstaller = true, bool silentInstall = false)
22+
{
23+
builder.Services.AddSingleton(new WebViewInstaller { Enabled = useInstaller, SilentInstall = silentInstall });
24+
25+
return builder;
26+
}
27+
28+
/// <summary>
29+
/// Adds chromium dev tools to the application.
30+
/// </summary>
31+
/// <param name="builder">The <see cref="BlazorDesktopHostBuilder"/>.</param>
32+
/// <returns>A reference to the <paramref name="builder"/> after the operation has completed.</returns>
33+
public static BlazorDesktopHostBuilder UseDeveloperTools(this BlazorDesktopHostBuilder builder)
34+
{
35+
builder.Services.AddBlazorWebViewDeveloperTools();
36+
37+
return builder;
38+
}
39+
}

0 commit comments

Comments
 (0)