Обзор:
Начните с прикрепления открытого исходного ASP.NET адреса GitHub Core
Вход по гиперссылке виден.
Вход по гиперссылке виден.
После создания нового проекта ASP.NET Core 3.1 код программы выглядит следующим образом:
Мы глубоко изучили код, совмещённый с исходным кодом GitHub.
Код хоста:Вход по гиперссылке виден.
Метод CreateDefaultBuilder
Здесь мы создаём объект HostBuilder, который наследует от IHostBuilder, и добавляем системные делегаты, такие как :appsettings.json, appsettings. {env. EnvironmentName}.json конфигурационный файл, который в конечном итоге вернёт: интерфейс IHostBuilder.
Код HostBuilder:Вход по гиперссылке виден.
В конечном итоге будет вызван метод Build.
Публичный IHost Build()
{ если (_hostBuilt) { throw new InvalidOperationException(SR. BuildCalled); } _hostBuilt = истинно;
BuildHostConfiguration(); СоздатьХостингОкружение(); CreateHostBuilderContext(); BuildAppConfiguration(); CreateServiceProvider();
возврат _appServices.GetRequiredService<IHost>();
} Метод BuildHostConfiguration
частный IConfiguration _hostConfiguration; IConfigurationBuilder configBuilder = новый ConfigurationBuilder() Вызовите делегата для добавления конфигурации
Метод CreateHostingEnvironment
Private HostingEnvironment _hostingEnvironment; _hostingEnvironment = новый HostingEnvironment()
{ ApplicationName = _hostConfiguration[HostDefaults.ApplicationKey], EnvironmentName = _hostConfiguration[HostDefaults.EnvironmentKey] ?? Окружения. Производство, ContentRootPath = ResolveContentRootPath(_hostConfiguration[HostDefaults.ContentRootKey], AppContext.BaseDirectory), }; CreateHostBuilderContext method
приватный HostBuilderContext _hostBuilderContext; _hostBuilderContext = новый HostBuilderContext(Properties)
{ HostingEnvironment = _hostingEnvironment, Конфигурация = _hostConfiguration }; Метод BuildAppConfiguration
Интегрируйте конфигурационную информацию снова
IConfigurationBuilder configBuilder = новый ConfigurationBuilder() . SetBasePath(_hostingEnvironment.ContentRootPath) . AddConfiguration(_hostConfiguration, shouldDisposeConfiguration: true); _appConfiguration = configBuilder.Build(); _hostBuilderContext.Конфигурация = _appConfiguration; Метод CreateServiceProvider
var services = новый ServiceCollection(); Зарегистрируйте сервис, вызовите делегата и добавьте пользовательский сервис.
Метод расширения GenerricHostBuilderExtensions
Вход по гиперссылке виден.
ConfigureWebHost extension method
Для регистрации GenericWebHostService как бэкенд-сервиса:
Строитель. ConfigureServices((context, services) => services. <GenericWebHostService>AddHostedService()); Код GenericWebHostService:Вход по гиперссылке виден.
public async Task StartAsync(CancellationToken cancellationToken) { HostingEventSource.Log.HostStart();
var serverAddressesFeature = Server.Features.Get<IServerAddressesFeature>(); var addresses = serverAddressesFeature?. Адреса; если (адреса != null && !адреса. IsReadOnly и адреса. Count == 0) { var urls = Configuration[WebHostDefaults.ServerUrlsKey]; если (!string. IsNullOrEmpty(urls)) { serverAddressesFeature!. PreferHostingUrls = WebHostUtilities.ParseBool(Configuration, WebHostDefaults.PreferHostingUrlsKey);
foreach (значение var в URL. Split('; ', StringSplitOptions.RedeleEmptyEntries)) { адреса. Add(value); } } }
ЗапроситьДелегировать? применение = null;
Попробуй { var configure = Options.ConfigureApplication;
if (configure == null) { throw new InvalidOperationException($"No application configurened. Пожалуйста, укажите приложение через IWebHostBuilder.UseStartup, IWebHostBuilder.Configure, или укажите ассембл запуска через {nameof(WebHostDefaults.StartupAssemblyKey)} в разделе конфигурация веб-хоста.»); }
var builder = ApplicationBuilderFactory.CreateBuilder(Server.Features);
foreach (var filter в StartupFilters.Reverse()) { configure = filter. Configure(configure); }
configure(builder);
Постройте конвейер запросов приложение = конструктор. Build(); } catch (исключение, например) { Logger.ApplicationError(ex);
если (! Options.WebHostOptions.CaptureStartupErrors) { бросать; }
var showDetailedErrors = HostingEnvironment.IsDevelopment() || Options.WebHostOptions.DetailedErrors;
application = ErrorPageBuilder.BuildErrorPageApplication(HostingEnvironment.ContentRootFileProvider, Logger, showDetailedErrors, ex); }
var httpApplication = новый HostingApplication (application, Logger, DiagnosticListener, HttpContextFactory);
ожидать Server.StartAsync(httpApplication, cancellationToken);
if (адреса != null) { foreach (VAR адрес в адресах) { LifetimeLogger.ListeningOnAddress(адрес); } }
if (Logger.IsEnabled(LogLevel.Debug)) { foreach (var assembly in Options.WebHostOptions.GetFinalHostingStartupAssemblies()) { Logger.StartupAssemblyLoaded(ассемблер); } }
if (Options.HostingStartupExceptions != null) { foreach (var exception in Options.HostingStartupExceptions.InnerExceptions) { Logger.HostingStartupAssemblyError(исключение); } } }
var webhostBuilder = новый GenerricWebHostBuilder(builder, webHostBuilderOptions); Вход по гиперссылке виден.
Метод расширения WebHostBuilderExtensions
Предоставляет объект startupType для вызовов IWebHostBuilder.
этот IWebHostBuilder hostBuilder if (hostBuilder is ISupportsStartup supportsStartup)
{ return supportsStartup.UseStartup(startupType);
} Вход по гиперссылке виден.
GenericWebHostBuilder Private Method GenericWebHostBuilder
Динамически инстанцируйте наш объект Startup:
Пример ?? = ActivatorUtilities.CreateInstance(новый HostServiceProvider(webHostBuilderContext), startupType); Контекст. Свойства[_startupKey] = экземпляр; Ищите метод ConfigureServices
var configureServicesBuilder = StartupLoader.FindConfigureServicesDelegate(startupType, context. HostingEnvironment.EnvironmentName); var configureServices = configureServicesBuilder.Build(instance);
внутренний статический 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); вернуть новый ConfigureServicesBuilder(servicesMethod); Ищите метод ConfigureContainer
var configureContainerBuilder = StartupLoader.FindConfigureContainerDelegate(startupType, context. HostingEnvironment.EnvironmentName);
внутренний статический ConfigureContainerBuilder FindConfigureContainerDelegate([DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)] Type startupType, строка environmentName) { var configureMethod = FindMethod(startupType, "Configure{0}Container", environmentName, typeof(void), required: false); вернуть новый ConfigureContainerBuilder(configureMethod); } Ищите метод Configure
configureBuilder = StartupLoader.FindConfigureDelegate(startupType, context. HostingEnvironment.EnvironmentName);
внутренний статический ConfigureBuilder FindConfigureDelegate([DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)] Type startupType, string environmentName)
{ var configureMethod = FindMethod(startupType, "Configure{0}", environmentName, typeof(void), required: true)!; вернуть новый ConfigureBuilder(configureMethod);
} Исходный код вызывается методом ConfigureBuilder Build, а исходный код выглядит следующим образом:
Частный класс ConfigureBuilder { public ConfigureBuilder(MethodInfo configure) { MethodInfo = конфигурировать; }
public MethodInfo MethodInfo { get; }
<IApplicationBuilder> Публичный Action Build (экземпляр объекта) { return (applicationBuilder) => Invoke (экземпляр, applicationBuilder); }
private void Invoke (object instance, IApplicationBuilder builder) { var serviceProvider = builder. ApplicationsServices; var parameterInfos = MethodInfo.GetParameters(); var parameters = новый объект[parameterInfos.Length]; для (индекс var = 0; index < parameterInfos.Length; index++) { var parameterInfo = parameterInfos[index]; if (parameterInfo.ParameterType == typeof(IApplicationBuilder)) { parameters[index] = конструктор; } Другое { Попробуй { parameters[index] = serviceProvider.GetRequiredService(parameterInfo.ParameterType); } catch (исключение, например) { throw new InvalidOperationException( Resources.FormatMiddlewareFilter_ServiceResolutionFail( parameterInfo.ParameterType.FullName, parameterInfo.Name, MethodInfo.Name, MethodInfo.DeclamingType.FullName), ex); } } } MethodInfo.Invoke (экземпляр, параметры); } } Метод запуска
Адрес метода расширения HostExtensions:
Вход по гиперссылке виден.
В конце концов звонит:
/// <summary> Запускает приложение и возвращает задачу, которая завершается только при срабатывании токена или отключении. /// </summary> <param name="host">The <see cref="IHost"/> для запуска</param>. <param name="token">Токен для запуска выключения</param>. <returns><см. cref="Задача"/> представляет асинхронную операцию.</returns> публичный статический асинхронный Task RunAsync (этот хост IHost, токен CancellationToken = по умолчанию) { Попробуй { Ждите хозяина. StartAsync(токен). ConfigureAwait (ложно);
Ждите хозяина. WaitForShutdownAsync(token). ConfigureAwait (ложно); } наконец-то { если (хост — IAsyncDisposable asyncDisposable) { ждать asyncDisposable.DisposeAsync(). ConfigureAwait (ложно); } Другое { Ведущий. Dispose(); }
} } Раньше, когда я создавал сервис, я регистрировался на сервис IHost, и код был следующим:
Услуги. <IHost>AddSingleton(_ => { Вернуть новый Internal.Host(_appServices, _appServices.GetRequiredService<IHostApplicationLifetime>(), _appServices.GetRequiredService<ILogger<Internal.Host>>(), _appServices.GetRequiredService<IHostLifetime>(), _appServices.GetRequiredService<<HostOptions>IOptions>()); }); Метод StartAsync
Адрес:Вход по гиперссылке виден.
public async Task StartAsync(CancellationToken cancellationToken = по умолчанию) { _logger. Starting();
используя var combinedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _applicationLifetime.ApplicationStopping); CancellationToken combinedCancellationToken = combinedCancellationTokenSource.Token;
Ожидайте _hostLifetime.WaitForStartAsync(combinedCancellationToken). ConfigureAwait (ложно);
combinedCancellationToken.ThrowIfCancellationRequested(); _hostedServices = Services.GetService<IEnumerable<IHostedService>>();
foreach (IHostedService hostedService в _hostedServices) { // Fire IHostedService.Start waitit hostedService.StartAsync(combinedCancellationToken). ConfigureAwait (ложно);
если (hostedService — это BackgroundService backgroundService) { _ = HandleBackgroundException(backgroundService); } }
Fire IHostApplicationLife.Started _applicationLifetime.NotifyStarted();
_logger. Start(); } (Конец)
|