1
1
// Licensed to the .NET Foundation under one or more agreements.
2
2
// The .NET Foundation licenses this file to you under the MIT license.
3
3
4
+ using System . Diagnostics ;
4
5
using Microsoft . Extensions . Configuration ;
5
6
using Microsoft . Extensions . DependencyInjection ;
6
- using Microsoft . Extensions . FileProviders ;
7
7
using Microsoft . Extensions . Hosting ;
8
8
9
9
namespace Microsoft . AspNetCore . Hosting ;
10
10
11
11
// This exists solely to bootstrap the configuration
12
12
internal sealed class BootstrapHostBuilder : IHostBuilder
13
13
{
14
- private readonly IServiceCollection _services ;
14
+ private readonly HostApplicationBuilder _builder ;
15
+
15
16
private readonly List < Action < IConfigurationBuilder > > _configureHostActions = new ( ) ;
16
17
private readonly List < Action < HostBuilderContext , IConfigurationBuilder > > _configureAppActions = new ( ) ;
17
18
private readonly List < Action < HostBuilderContext , IServiceCollection > > _configureServicesActions = new ( ) ;
18
19
19
- private readonly List < Action < IHostBuilder > > _remainingOperations = new ( ) ;
20
-
21
- public BootstrapHostBuilder ( IServiceCollection services , IDictionary < object , object > properties )
20
+ public BootstrapHostBuilder ( HostApplicationBuilder builder )
22
21
{
23
- _services = services ;
22
+ _builder = builder ;
24
23
25
- Properties = properties ;
24
+ foreach ( var descriptor in _builder . Services )
25
+ {
26
+ if ( descriptor . ServiceType == typeof ( HostBuilderContext ) )
27
+ {
28
+ Context = ( HostBuilderContext ) descriptor . ImplementationInstance ! ;
29
+ break ;
30
+ }
31
+ }
32
+
33
+ if ( Context is null )
34
+ {
35
+ throw new InvalidOperationException ( $ "{ nameof ( HostBuilderContext ) } must exist in the { nameof ( IServiceCollection ) } ") ;
36
+ }
26
37
}
27
38
28
- public IDictionary < object , object > Properties { get ; }
39
+ public IDictionary < object , object > Properties => Context . Properties ;
29
40
30
- public IHost Build ( )
41
+ public HostBuilderContext Context { get ; }
42
+
43
+ public IHostBuilder ConfigureHostConfiguration ( Action < IConfigurationBuilder > configureDelegate )
31
44
{
32
- // HostingHostBuilderExtensions.ConfigureDefaults should never call this.
33
- throw new InvalidOperationException ( ) ;
45
+ _configureHostActions . Add ( configureDelegate ?? throw new ArgumentNullException ( nameof ( configureDelegate ) ) ) ;
46
+ return this ;
34
47
}
35
48
36
49
public IHostBuilder ConfigureAppConfiguration ( Action < HostBuilderContext , IConfigurationBuilder > configureDelegate )
@@ -39,123 +52,70 @@ public IHostBuilder ConfigureAppConfiguration(Action<HostBuilderContext, IConfig
39
52
return this ;
40
53
}
41
54
42
- public IHostBuilder ConfigureContainer < TContainerBuilder > ( Action < HostBuilderContext , TContainerBuilder > configureDelegate )
55
+ public IHostBuilder ConfigureServices ( Action < HostBuilderContext , IServiceCollection > configureDelegate )
43
56
{
44
- // This is not called by HostingHostBuilderExtensions.ConfigureDefaults currently, but that could change in the future.
45
- // If this does get called in the future, it should be called again at a later stage on the ConfigureHostBuilder.
46
- if ( configureDelegate is null )
47
- {
48
- throw new ArgumentNullException ( nameof ( configureDelegate ) ) ;
49
- }
50
-
51
- _remainingOperations . Add ( hostBuilder => hostBuilder . ConfigureContainer < TContainerBuilder > ( configureDelegate ) ) ;
57
+ _configureServicesActions . Add ( configureDelegate ?? throw new ArgumentNullException ( nameof ( configureDelegate ) ) ) ;
52
58
return this ;
53
59
}
54
60
55
- public IHostBuilder ConfigureHostConfiguration ( Action < IConfigurationBuilder > configureDelegate )
61
+ public IHost Build ( )
56
62
{
57
- _configureHostActions . Add ( configureDelegate ?? throw new ArgumentNullException ( nameof ( configureDelegate ) ) ) ;
58
- return this ;
63
+ // ConfigureWebHostDefaults should never call this.
64
+ throw new InvalidOperationException ( ) ;
59
65
}
60
66
61
- public IHostBuilder ConfigureServices ( Action < HostBuilderContext , IServiceCollection > configureDelegate )
67
+ public IHostBuilder ConfigureContainer < TContainerBuilder > ( Action < HostBuilderContext , TContainerBuilder > configureDelegate )
62
68
{
63
- // HostingHostBuilderExtensions.ConfigureDefaults calls this via ConfigureLogging
64
- _configureServicesActions . Add ( configureDelegate ?? throw new ArgumentNullException ( nameof ( configureDelegate ) ) ) ;
65
- return this ;
69
+ // ConfigureWebHostDefaults should never call this.
70
+ throw new InvalidOperationException ( ) ;
66
71
}
67
72
68
73
public IHostBuilder UseServiceProviderFactory < TContainerBuilder > ( IServiceProviderFactory < TContainerBuilder > factory ) where TContainerBuilder : notnull
69
74
{
70
- // This is not called by HostingHostBuilderExtensions.ConfigureDefaults currently, but that could change in the future.
71
- // If this does get called in the future, it should be called again at a later stage on the ConfigureHostBuilder.
72
- if ( factory is null )
73
- {
74
- throw new ArgumentNullException ( nameof ( factory ) ) ;
75
- }
76
-
77
- _remainingOperations . Add ( hostBuilder => hostBuilder . UseServiceProviderFactory < TContainerBuilder > ( factory ) ) ;
78
- return this ;
75
+ // ConfigureWebHostDefaults should never call this.
76
+ throw new InvalidOperationException ( ) ;
79
77
}
80
78
81
79
public IHostBuilder UseServiceProviderFactory < TContainerBuilder > ( Func < HostBuilderContext , IServiceProviderFactory < TContainerBuilder > > factory ) where TContainerBuilder : notnull
82
80
{
83
- // HostingHostBuilderExtensions.ConfigureDefaults calls this via UseDefaultServiceProvider
84
- // during the initial config stage. It should be called again later on the ConfigureHostBuilder.
85
- if ( factory is null )
86
- {
87
- throw new ArgumentNullException ( nameof ( factory ) ) ;
88
- }
89
-
90
- _remainingOperations . Add ( hostBuilder => hostBuilder . UseServiceProviderFactory < TContainerBuilder > ( factory ) ) ;
91
- return this ;
81
+ // ConfigureWebHostDefaults should never call this.
82
+ throw new InvalidOperationException ( ) ;
92
83
}
93
84
94
- public ( HostBuilderContext , ConfigurationManager ) RunDefaultCallbacks ( ConfigurationManager configuration , HostBuilder innerBuilder )
85
+ public ServiceDescriptor RunDefaultCallbacks ( )
95
86
{
96
- var hostConfiguration = new ConfigurationManager ( ) ;
97
-
98
87
foreach ( var configureHostAction in _configureHostActions )
99
88
{
100
- configureHostAction ( hostConfiguration ) ;
89
+ configureHostAction ( _builder . Configuration ) ;
101
90
}
102
91
103
- // This is the hosting environment based on configuration we've seen so far.
104
- var hostingEnvironment = new HostingEnvironment ( )
105
- {
106
- // ApplicationKey is always configured by WebApplicationOptions, so it's never expected to be null
107
- ApplicationName = hostConfiguration [ HostDefaults . ApplicationKey ] ! ,
108
- EnvironmentName = hostConfiguration [ HostDefaults . EnvironmentKey ] ?? Environments . Production ,
109
- ContentRootPath = HostingPathResolver . ResolvePath ( hostConfiguration [ HostDefaults . ContentRootKey ] ) ,
110
- } ;
111
-
112
- hostingEnvironment . ContentRootFileProvider = new PhysicalFileProvider ( hostingEnvironment . ContentRootPath ) ;
113
-
114
- // Normalize the content root setting for the path in configuration
115
- hostConfiguration [ HostDefaults . ContentRootKey ] = hostingEnvironment . ContentRootPath ;
116
-
117
- var hostContext = new HostBuilderContext ( Properties )
118
- {
119
- Configuration = hostConfiguration ,
120
- HostingEnvironment = hostingEnvironment ,
121
- } ;
122
-
123
- // Split the host configuration and app configuration so that the
124
- // subsequent callback don't get a chance to modify the host configuration.
125
- configuration . SetBasePath ( hostingEnvironment . ContentRootPath ) ;
126
-
127
- // Chain the host configuration and app configuration together.
128
- configuration . AddConfiguration ( hostConfiguration , shouldDisposeConfiguration : true ) ;
129
-
130
92
// ConfigureAppConfiguration cannot modify the host configuration because doing so could
131
93
// change the environment, content root and application name which is not allowed at this stage.
132
94
foreach ( var configureAppAction in _configureAppActions )
133
95
{
134
- configureAppAction ( hostContext , configuration ) ;
96
+ configureAppAction ( Context , _builder . Configuration ) ;
135
97
}
136
98
137
- // Update the host context, everything from here sees the final
138
- // app configuration
139
- hostContext . Configuration = configuration ;
140
-
141
99
foreach ( var configureServicesAction in _configureServicesActions )
142
100
{
143
- configureServicesAction ( hostContext , _services ) ;
101
+ configureServicesAction ( Context , _builder . Services ) ;
144
102
}
145
103
146
- foreach ( var callback in _remainingOperations )
104
+ ServiceDescriptor ? genericWebHostServiceDescriptor = null ;
105
+
106
+ for ( int i = _builder . Services . Count - 1 ; i >= 0 ; i -- )
147
107
{
148
- callback ( innerBuilder ) ;
108
+ var descriptor = _builder . Services [ i ] ;
109
+ if ( descriptor . ServiceType == typeof ( IHostedService ) )
110
+ {
111
+ Debug . Assert ( descriptor . ImplementationType ? . Name == "GenericWebHostService" ) ;
112
+
113
+ genericWebHostServiceDescriptor = descriptor ;
114
+ _builder . Services . RemoveAt ( i ) ;
115
+ break ;
116
+ }
149
117
}
150
118
151
- return ( hostContext , hostConfiguration ) ;
152
- }
153
-
154
- private class HostingEnvironment : IHostEnvironment
155
- {
156
- public string EnvironmentName { get ; set ; } = default ! ;
157
- public string ? ApplicationName { get ; set ; }
158
- public string ContentRootPath { get ; set ; } = default ! ;
159
- public IFileProvider ContentRootFileProvider { get ; set ; } = default ! ;
119
+ return genericWebHostServiceDescriptor ?? throw new InvalidOperationException ( $ "GenericWebHostedService must exist in the { nameof ( IServiceCollection ) } ") ;
160
120
}
161
121
}
0 commit comments