This article is a mirror article of machine translation, please click here to jump to the original article.

View: 59583|Reply: 1

[Source] ASP.NET Core (7) In-depth analysis of the framework source code

[Copy link]
Posted on 2021-3-24 13:43:28 | | |
Review:

ASP.NET Core (VI) DI manually obtains the method of injecting objects
https://www.itsvse.com/thread-9595-1-1.html

ASP.NET Core (five) is based on CAP distributed transactions
https://www.itsvse.com/thread-9593-1-1.html

ASP.NET Core(4) filter unified ModelState model validation
https://www.itsvse.com/thread-9589-1-1.html

ASP.NET Core (iii) Dynamically create instances using ActivatorUtilities
https://www.itsvse.com/thread-9488-1-1.html

ASP.NET Core (2) Restart the application by code
https://www.itsvse.com/thread-9480-1-1.html

ASP.NET Core (1) uses Redis caching
https://www.itsvse.com/thread-9393-1-1.html
Start by attaching the ASP.NET Core GitHub open source address

The hyperlink login is visible.
The hyperlink login is visible.


asp.net Core source code address
https://www.itsvse.com/thread-9394-1-1.html


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)




Previous:Late newcomer reports
Next:.NET Core error in Linux Failure processing application bundle
Posted on 2021-9-22 20:45:12 |
Learn to learn...
Disclaimer:
All software, programming materials or articles published by Code Farmer Network are only for learning and research purposes; The above content shall not be used for commercial or illegal purposes, otherwise, users shall bear all consequences. The information on this site comes from the Internet, and copyright disputes have nothing to do with this site. You must completely delete the above content from your computer within 24 hours of downloading. If you like the program, please support genuine software, purchase registration, and get better genuine services. If there is any infringement, please contact us by email.

Mail To:help@itsvse.com