Review:
Start by attaching the ASP.NET Core GitHub open source address
The hyperlink login is visible.
The hyperlink login is visible.
After creating a new project ASP.NET Core 3.1, the program code is as follows:
We took a deep dive into the entry code combined with the GitHub source code.
Host Code:The hyperlink login is visible.
CreateDefaultBuilder method
Here we instantiate a HostBuilder object, which inherits from IHostBuilder, and add system-defined delegates, such as :appsettings.json, appsettings. {env. EnvironmentName}.json configuration file, which will eventually return: IHostBuilder interface.
HostBuilder Code:The hyperlink login is visible.
The Build method will eventually be called.
public IHost Build()
{ if (_hostBuilt) { throw new InvalidOperationException(SR. BuildCalled); } _hostBuilt = true;
BuildHostConfiguration(); CreateHostingEnvironment(); CreateHostBuilderContext(); BuildAppConfiguration(); CreateServiceProvider();
return _appServices.GetRequiredService<IHost>();
} BuildHostConfiguration method
private IConfiguration _hostConfiguration; IConfigurationBuilder configBuilder = new ConfigurationBuilder() Call the delegate to add configuration in turn
CreateHostingEnvironment method
private HostingEnvironment _hostingEnvironment; _hostingEnvironment = new HostingEnvironment()
{ ApplicationName = _hostConfiguration[HostDefaults.ApplicationKey], EnvironmentName = _hostConfiguration[HostDefaults.EnvironmentKey] ?? Environments.Production, ContentRootPath = ResolveContentRootPath(_hostConfiguration[HostDefaults.ContentRootKey], AppContext.BaseDirectory), }; CreateHostBuilderContext method
private HostBuilderContext _hostBuilderContext; _hostBuilderContext = new HostBuilderContext(Properties)
{ HostingEnvironment = _hostingEnvironment, Configuration = _hostConfiguration }; BuildAppConfiguration method
Integrate the configuration information again
IConfigurationBuilder configBuilder = new ConfigurationBuilder() . SetBasePath(_hostingEnvironment.ContentRootPath) . AddConfiguration(_hostConfiguration, shouldDisposeConfiguration: true); _appConfiguration = configBuilder.Build(); _hostBuilderContext.Configuration = _appConfiguration; CreateServiceProvider method
var services = new ServiceCollection(); Register a service, call a delegate, and add a user-defined service.
GenericHostBuilderExtensions extension method
The hyperlink login is visible.
ConfigureWebHost extension method
To register GenericWebHostService as a backend service:
builder. ConfigureServices((context, services) => services. AddHostedService<GenericWebHostService>()); GenericWebHostService Code:The hyperlink login is visible.
public async Task StartAsync(CancellationToken cancellationToken) { HostingEventSource.Log.HostStart();
var serverAddressesFeature = Server.Features.Get<IServerAddressesFeature>(); var addresses = serverAddressesFeature?. Addresses; if (addresses != null && !addresses. IsReadOnly && addresses. Count == 0) { var urls = Configuration[WebHostDefaults.ServerUrlsKey]; if (!string. IsNullOrEmpty(urls)) { serverAddressesFeature!. PreferHostingUrls = WebHostUtilities.ParseBool(Configuration, WebHostDefaults.PreferHostingUrlsKey);
foreach (var value in urls. Split('; ', StringSplitOptions.RemoveEmptyEntries)) { addresses. Add(value); } } }
RequestDelegate? application = null;
try { var configure = Options.ConfigureApplication;
if (configure == null) { throw new InvalidOperationException($"No application configured. Please specify an application via IWebHostBuilder.UseStartup, IWebHostBuilder.Configure, or specifying the startup assembly via {nameof(WebHostDefaults.StartupAssemblyKey)} in the web host configuration."); }
var builder = ApplicationBuilderFactory.CreateBuilder(Server.Features);
foreach (var filter in StartupFilters.Reverse()) { configure = filter. Configure(configure); }
configure(builder);
// Build the request pipeline application = builder. Build(); } catch (Exception ex) { Logger.ApplicationError(ex);
if (! Options.WebHostOptions.CaptureStartupErrors) { throw; }
var showDetailedErrors = HostingEnvironment.IsDevelopment() || Options.WebHostOptions.DetailedErrors;
application = ErrorPageBuilder.BuildErrorPageApplication(HostingEnvironment.ContentRootFileProvider, Logger, showDetailedErrors, ex); }
var httpApplication = new HostingApplication(application, Logger, DiagnosticListener, HttpContextFactory);
await Server.StartAsync(httpApplication, cancellationToken);
if (addresses != null) { foreach (var address in addresses) { LifetimeLogger.ListeningOnAddress(address); } }
if (Logger.IsEnabled(LogLevel.Debug)) { foreach (var assembly in Options.WebHostOptions.GetFinalHostingStartupAssemblies()) { Logger.StartupAssemblyLoaded(assembly); } }
if (Options.HostingStartupExceptions != null) { foreach (var exception in Options.HostingStartupExceptions.InnerExceptions) { Logger.HostingStartupAssemblyError(exception); } } }
var webhostBuilder = new GenericWebHostBuilder(builder, webHostBuilderOptions); The hyperlink login is visible.
WebHostBuilderExtensions extension method
Provides a startupType object for IWebHostBuilder calls.
this IWebHostBuilder hostBuilder if (hostBuilder is ISupportsStartup supportsStartup)
{ return supportsStartup.UseStartup(startupType);
} The hyperlink login is visible.
GenericWebHostBuilder Private Method GenericWebHostBuilder
Dynamically instantiate our Startup object:
instance ?? = ActivatorUtilities.CreateInstance(new HostServiceProvider(webHostBuilderContext), startupType); context. Properties[_startupKey] = instance; Look for the ConfigureServices method
var configureServicesBuilder = StartupLoader.FindConfigureServicesDelegate(startupType, context. HostingEnvironment.EnvironmentName); var configureServices = configureServicesBuilder.Build(instance);
internal static ConfigureServicesBuilder FindConfigureServicesDelegate([DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)] Type startupType, string environmentName) { var servicesMethod = FindMethod(startupType, "Configure{0}Services", environmentName, typeof(IServiceProvider), required: false) ?? FindMethod(startupType, "Configure{0}Services", environmentName, typeof(void), required: false); return new ConfigureServicesBuilder(servicesMethod); Look for the ConfigureContainer method
var configureContainerBuilder = StartupLoader.FindConfigureContainerDelegate(startupType, context. HostingEnvironment.EnvironmentName);
internal static ConfigureContainerBuilder FindConfigureContainerDelegate([DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)] Type startupType, string environmentName) { var configureMethod = FindMethod(startupType, "Configure{0}Container", environmentName, typeof(void), required: false); return new ConfigureContainerBuilder(configureMethod); } Look for the Configure method
configureBuilder = StartupLoader.FindConfigureDelegate(startupType, context. HostingEnvironment.EnvironmentName);
internal static ConfigureBuilder FindConfigureDelegate([DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)] Type startupType, string environmentName)
{ var configureMethod = FindMethod(startupType, "Configure{0}", environmentName, typeof(void), required: true)!; return new ConfigureBuilder(configureMethod);
} Called by ConfigureBuilder's Build method, the source code is as follows:
private class ConfigureBuilder { public ConfigureBuilder(MethodInfo configure) { MethodInfo = configure; }
public MethodInfo MethodInfo { get; }
public Action<IApplicationBuilder> Build(object instance) { return (applicationBuilder) => Invoke(instance, applicationBuilder); }
private void Invoke(object instance, IApplicationBuilder builder) { var serviceProvider = builder. ApplicationServices; var parameterInfos = MethodInfo.GetParameters(); var parameters = new object[parameterInfos.Length]; for (var index = 0; index < parameterInfos.Length; index++) { var parameterInfo = parameterInfos[index]; if (parameterInfo.ParameterType == typeof(IApplicationBuilder)) { parameters[index] = builder; } else { try { parameters[index] = serviceProvider.GetRequiredService(parameterInfo.ParameterType); } catch (Exception ex) { throw new InvalidOperationException( Resources.FormatMiddlewareFilter_ServiceResolutionFail( parameterInfo.ParameterType.FullName, parameterInfo.Name, MethodInfo.Name, MethodInfo.DeclaringType.FullName), ex); } } } MethodInfo.Invoke(instance, parameters); } } Run method
HostingAbstractionsHostExtensions extension method address:
The hyperlink login is visible.
Eventually calls:
/// <summary> /// Runs an application and returns a Task that only completes when the token is triggered or shutdown is triggered. /// </summary> /// <param name="host">The <see cref="IHost"/> to run.</param> /// <param name="token">The token to trigger shutdown.</param> /// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns> public static async Task RunAsync(this IHost host, CancellationToken token = default) { try { await host. StartAsync(token). ConfigureAwait(false);
await host. WaitForShutdownAsync(token). ConfigureAwait(false); } finally { if (host is IAsyncDisposable asyncDisposable) { await asyncDisposable.DisposeAsync(). ConfigureAwait(false); } else { host. Dispose(); }
} } Previously, when I was building a service, I would register for the IHost service, and the code is as follows:
services. AddSingleton<IHost>(_ => { return new Internal.Host(_appServices, _appServices.GetRequiredService<IHostApplicationLifetime>(), _appServices.GetRequiredService<ILogger<Internal.Host>>(), _appServices.GetRequiredService<IHostLifetime>(), _appServices.GetRequiredService<IOptions<HostOptions>>()); }); StartAsync method
Address:The hyperlink login is visible.
public async Task StartAsync(CancellationToken cancellationToken = default) { _logger. Starting();
using var combinedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _applicationLifetime.ApplicationStopping); CancellationToken combinedCancellationToken = combinedCancellationTokenSource.Token;
await _hostLifetime.WaitForStartAsync(combinedCancellationToken). ConfigureAwait(false);
combinedCancellationToken.ThrowIfCancellationRequested(); _hostedServices = Services.GetService<IEnumerable<IHostedService>>();
foreach (IHostedService hostedService in _hostedServices) { // Fire IHostedService.Start await hostedService.StartAsync(combinedCancellationToken). ConfigureAwait(false);
if (hostedService is BackgroundService backgroundService) { _ = HandleBackgroundException(backgroundService); } }
// Fire IHostApplicationLifetime.Started _applicationLifetime.NotifyStarted();
_logger. Started(); } (End)
|