Recenzja:
Zacznij od dołączenia otwartego adresu GitHub ASP.NET Core
Logowanie do linku jest widoczne.
Logowanie do linku jest widoczne.
Po utworzeniu nowego projektu ASP.NET Core 3.1, kod programu wygląda następująco:
Dogłębnie przyjrzeliśmy się kodowi wejściowemu połączonemu z kodem źródłowym GitHuba.
Kod hosta:Logowanie do linku jest widoczne.
Metoda CreateDefaultBuilder
Tutaj instancjonujemy obiekt HostBuilder, który dziedziczy z IHostBuilder, i dodajemy delegatów definiowanych przez system, takich jak :appsettings.json, appsettings. {env. EnvironmentName}.json pliku konfiguracyjnego, który ostatecznie zwróci: interfejs IHostBuilder.
Kod HostBuilder:Logowanie do linku jest widoczne.
Metoda Build zostanie ostatecznie wywołana.
public IHost Build()
{ jeśli (_hostBuilt) { wyrzuć nowy InvalidOperationException(SR. BuildCalled); } _hostBuilt = prawdziwe;
BuildHostConfiguration(); CreateHostingEnvironment(); CreateHostBuilderContext(); BuildAppConfiguration(); CreateServiceProvider();
return _appServices.GetRequiredService<IHost>();
} Metoda BuildHostConfiguration
prywatna _hostConfiguration IConfiguracji; IConfigurationBuilder configBuilder = nowy ConfigurationBuilder() Wywołaj delegata, aby dodać konfigurację na kolej
Metoda CreateHostingEnvironment
prywatne HostingEnvironment _hostingEnvironment; _hostingEnvironment = nowy HostEnvironment()
{ ApplicationName = _hostConfiguration[HostDefaults.ApplicationKey], EnvironmentName = _hostConfiguration[HostDefaults.EnvironmentKey] ?? Środowiska. Produkcja, ContentRootPath = ResolveContentRootPath(_hostConfiguration[HostDefaults.ContentRootKey], AppContext.BaseDirectory), }; Metoda CreateHostBuilderContext
prywatny HostBuilderContext _hostBuilderContext; _hostBuilderContext = nowy HostBuilderContext(Właściwości)
{ HostEnvironment = _hostingEnvironment, Konfiguracja = _hostConfiguration }; Metoda BuildAppConfiguration
Ponownie integruj informacje konfiguracyjne
IConfigurationBuilder configBuilder = nowy ConfigurationBuilder() . SetBasePath(_hostingEnvironment.ContentRootPath) . AddConfiguration(_hostConfiguration, shouldDisposeConfiguration: true); _appConfiguration = configBuilder.Build(); _hostBuilderContext.Konfiguracja = _appConfiguration; Metoda CreateServiceProvider
var services = new ServiceCollection(); Zarejestruj usługę, wywołaj delegata i dodaj usługę zdefiniowaną przez użytkownika.
Metoda rozszerzenia GenericHostBuilderExtensions
Logowanie do linku jest widoczne.
Metoda rozszerzenia ConfigureWebHost
Aby zarejestrować GenericWebHostService jako usługę backendową:
Budowniczcie. ConfigureServices((context, services) => services. AddHostedService<GenericWebHostService>()); Kod GenericWebHostService:Logowanie do linku jest widoczne.
publicznie asynchroniczne zadanie StartAsync(CancellationToken cancellationToken) { HostingEventSource.Log.HostStart();
var serverAddressesFeature = Server.Features.Get<IServerAddressesFeature>(); var addresses = serverAddressesFeature?. Adresy; if (adresuje != adresy null & !. IsReadOnly & adresy. Count == 0) { var urls = Configuration[WebHostDefaults.ServerUrlsKey]; if (!string. IsNullOrEmpty(urls)) { serwerAddressesFeature!. PreferHostingUrls = WebHostUtilities.ParseBool(Configuration, WebHostDefaults.PreferHostingUrlsKey);
foreach (wartość var w URL-ach. Split('; ', StringSplitOptions.RemoveEmptyEntries)) { adresy. add(value); } } }
RequestDelegate? zastosowanie = null;
spróbuj { var configure = Options.ConfigureApplication;
if (configure == null) { wyrzuć nowy InvalidOperationException($"Nie skonfigurowana żadna aplikacja. Proszę określić aplikację za pomocą IWebHostBuilder.UseStartup, IWebHostBuilder.Configure, lub określić asembl startowy za pomocą {nameof(WebHostDefaults.StartupAssemblyKey)} w konfiguracja hosta webowego."); }
var builder = ApplicationBuilderFactory.CreateBuilder(Server.Features);
foreach (var filter in StartupFilters.Reverse()) { configure = filter. konfiguruj (konfiguruj); }
configure(builder);
Buduj potok żądań zastosowanie = twórca. build(); } złapanie (Wyjątek ex) { Logger.ApplicationError(ex);
jeśli (! Options.WebHostOptions.CaptureStartupErrors) { rzut; }
var showDetailedErrors = HostEnvironment.IsDevelopment() || Options.WebHostOptions.SzczegółoweBłędy;
application = ErrorPageBuilder.BuildErrorPageApplication(HostingEnvironment.ContentRootFileProvider, Logger, showDetailedErrors, ex); }
var httpApplication = nowy HostingApplication(application, Logger, DiagnosticListener, HttpContextFactory);
await Server.StartAsync(httpApplication, cancellationToken);
if (adresuje != null) { foreach (adres var w adresach) { LifetimeLogger.ListeningOnAddress(address); } }
if (Logger.IsEnabled(LogLevel.Debug)) { foreach (var assembly in Options.WebHostOptions.GetFinalHostingStartupAssemblies()) { Logger.StartupAssemblyLoaded(assembly); } }
if (Options.HostingStartupExceptions != null) { foreach (wyjątek zmienny w Options.HostingStartupExceptions.InnerExceptions) { Logger.HostingStartupAssemblyError(exception); } } }
var webhostBuilder = nowy GenericWebHostBuilder(builder, webHostBuilderOptions); Logowanie do linku jest widoczne.
Metoda rozszerzenia WebHostBuilderExtensions
Zapewnia obiekt startupType dla wywołań IWebHostBuilder.
ten IWebHostBuilder hostBuilder jeśli (hostBuilder is ISupportsStartup supportsStartup)
{ return supportsStartup.UseStartup(startupType);
} Logowanie do linku jest widoczne.
GenericWebHostBuilder Metoda prywatna GenericWebHostBuilder
Dynamicznie instancjonuj nasz obiekt Startup:
przypadek?? = ActivatorUtilities.CreateInstance(nowy HostServiceProvider(webHostBuilderContext), startType); kontekst. Właściwości[_startupKey] = instancja; Szukaj metody ConfigureServices
var configureServicesBuilder = StartupLoader.FindConfigureServicesDelegate(startupType, context. HostingEnvironment.EnvironmentName); var configureServices = configureServicesBuilder.Build(instance);
internal static ConfigureServicesBuilder FindConfigureServicesDelegate([DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)] Wpis startupType, string environmentName) { var servicesMethod = FindMethod(startupType, "Configure{0}Services", environmentName, typeof(IServiceProvider), required: false) ?? FindMethod(startType, "Configure{0}Services", environmentName, typeof(void), required: false); return new ConfigureServicesBuilder(servicesMethod); Szukaj metody ConfigureContainer
var configureContainerBuilder = StartupLoader.FindConfigureContainerDelegate(startupType, context. HostingEnvironment.EnvironmentName);
internal static ConfigureContainerBuilder FindConfigureContainerDelegate([DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)] Wpisz startupType, string environmentName) { var configureMethod = FindMethod(startupType, "Configure{0}Container", environmentName, typeof(void), required: false); return new ConfigureContainerBuilder(configureMethod); } Poszukaj metody Configure
configureBuilder = StartupLoader.FindConfigureDelegate(startType, context. HostingEnvironment.EnvironmentName);
internal static ConfigureBuilder FindConfigureDelegate([DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)] Wpisz startupType, string environmentName)
{ var configureMethod = FindMethod(startupType, "Configure{0}", environmentName, typeof(void), required: true)!; return new ConfigureBuilder(configureMethod);
} Generowany metodą Build ConfigureBuilder, kod źródłowy wygląda następująco:
Prywatna klasa ConfigureBuilder { public ConfigureBuilder(MethodInfo configure) { MethodInfo = konfigurować; }
public MethodInfo MethodInfo { get; }
public<IApplicationBuilder> Action Build (instancja obiektu) { return (applicationBuilder) => Invoke(instancja, applicationBuilder); }
private void Invoke(instancja obiektu, IApplicationBuilder builder) { var serviceProvider = builder. ApplicationServices; var parameterInfos = MethodInfo.GetParameters(); parametry var = nowy obiekt[parameterInfos.Length]; dla (indeks zmienny = 0; index < parametrInfos.Length; indeks++) { var parameterInfo = parameterInfos[index]; if (parameterInfo.ParameterType == typeof(IApplicationBuilder)) { parametry[index] = budownicza; } else { spróbuj { parameters[index] = serviceProvider.GetRequiredService(parameterInfo.ParameterType); } złapanie (Wyjątek ex) { throw new InvalidOperationException( Resources.FormatMiddlewareFilter_ServiceResolutionFail( parameterInfo.ParameterType.FullName, parameterInfo.Name, MethodInfo.Name, MethodInfo.DeclaringType.FullName), ex); } } } MethodInfo.Invoke(instancja, parametry); } } Metoda uruchomienia
Adres metody rozszerzenia HostingAbstractionsHostExtensions:
Logowanie do linku jest widoczne.
Ostatecznie dzwoni:
/// <summary> Uruchamia aplikację i zwraca zadanie, które kończy się tylko po wyzwoleniu tokena lub wyłączeniu. /// </summary> <nazwa parametrów="host">The <see cref="IHost"/> do uruchomienia.</param> <nazwa parametru="token">Token wywołujący wyłączenie.</param> <returns><zobacz cref="Task"/> reprezentuje operację asynchroniczną.</returns> publiczny statyczny asynchroniczny Task RunAsync (ten IHost host, token CancellationToken = domyślny) { spróbuj { Czekajcie na gospodarza. StartAsync(token). ConfigureAwait(false);
Czekajcie na gospodarza. WaitForShutdownAsync(token). ConfigureAwait(false); } W końcu { if (host is IAsyncDisposable asyncDisposable) { await asyncDisposable.DisposeAsync(). ConfigureAwait(false); } else { gospodarza. Dispose(); }
} } Wcześniej, gdy tworzyłem usługę, rejestrowałem się do usługi IHost, a kod był następujący:
usługi. AddSingleton<IHost>(_ => { return new Internal.Host(_appServices, _appServices.GetRequiredService<IHostApplicationLifetime>(), _appServices.GetRequiredService<ILogger<Internal.Host>>(), _appServices.GetRequiredService<IHostLifetime>(), _appServices.GetRequiredService<IOptions<HostOptions>>()); }); Metoda StartAsync
Adres:Logowanie do linku jest widoczne.
publicznie asynchroniczne Zadanie StartAsync(CancellationToken cancellationToken = domyślne) { _logger. Starting();
używając 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 w _hostedServices) { // Fire IHostedService.Start await hostedService.StartAsync(combinedCancellationToken). ConfigureAwait(false);
jeśli (hostedService is BackgroundService backgroundService) { _ = HandleBackgroundException(backgroundService); } }
// Fire IHostApplicationLifetime.Started _applicationLifetime.NotifyStarted();
_logger. Started(); } (Koniec)
|