in src/WebJobs.Script/ScriptHostBuilderExtensions.cs [172:366]
public static IHostBuilder AddScriptHostCore(this IHostBuilder builder, ScriptApplicationHostOptions applicationHostOptions, Action<IWebJobsBuilder> configureWebJobs = null, ILoggerFactory loggerFactory = null)
{
var skipHostInitialization = builder.Properties.ContainsKey(ScriptConstants.SkipHostInitializationKey);
builder.ConfigureServices((context, services) =>
{
services.AddSingleton<ExternalConfigurationStartupValidator>();
services.AddSingleton<IHostedService>(s =>
{
if (!skipHostInitialization)
{
var environment = s.GetService<IEnvironment>();
// This key will not be here if we don't have any external configuration startups registered
if (context.Properties.TryGetValue(ConfigurationSnapshotKey, out object originalConfigObject) &&
originalConfigObject is IConfigurationRoot originalConfig)
{
context.Properties.Remove(ConfigurationSnapshotKey);
// Validate the config for anything that needs the Scale Controller.
// Including Core Tools as a warning during development time.
if (environment.IsWindowsConsumption() ||
environment.IsAnyLinuxConsumption() ||
(environment.IsWindowsElasticPremium() && !environment.IsRuntimeScaleMonitoringEnabled()) ||
environment.IsCoreTools())
{
var validator = s.GetService<ExternalConfigurationStartupValidator>();
var logger = s.GetService<ILoggerFactory>().CreateLogger<ExternalConfigurationStartupValidator>();
return new ExternalConfigurationStartupValidatorService(validator, originalConfig, environment, logger);
}
}
}
return NullHostedService.Instance;
});
// Wire this up early so that any early worker logs are guaranteed to be flushed if any other
// IHostedService has a slow startup.
services.AddSingleton<IHostedService, WorkerConsoleLogService>();
});
builder.ConfigureWebJobs((context, webJobsBuilder) =>
{
// Built in binding registrations
webJobsBuilder.AddExecutionContextBinding(o =>
{
o.AppDirectory = applicationHostOptions.ScriptPath;
})
.AddHttp()
.AddTimersWithStorage()
.AddManualTrigger()
.AddWarmup();
var bundleManager = context.Properties.GetAndRemove<IExtensionBundleManager>(BundleManagerKey);
webJobsBuilder.Services.AddSingleton<IExtensionBundleManager>(_ => bundleManager);
if (!skipHostInitialization)
{
var webJobsBuilderContext = new WebJobsBuilderContext
{
Configuration = context.Configuration,
EnvironmentName = context.HostingEnvironment.EnvironmentName,
ApplicationRootPath = applicationHostOptions.ScriptPath
};
// Only set our external startup if we're not suppressing host initialization
// as we don't want to load user assemblies otherwise.
var locator = context.Properties.GetAndRemove<ScriptStartupTypeLocator>(StartupTypeLocatorKey);
try
{
webJobsBuilder.UseExternalStartup(locator, webJobsBuilderContext, loggerFactory);
}
catch (Exception ex)
{
string appInsightsConnStr = GetConfigurationValue(EnvironmentSettingNames.AppInsightsConnectionString, context.Configuration);
string appInsightsAuthStr = GetConfigurationValue(EnvironmentSettingNames.AppInsightsAuthenticationString, context.Configuration);
RecordAndThrowExternalStartupException("Error configuring services in an external startup class.", ex, loggerFactory, appInsightsConnStr, appInsightsAuthStr);
}
}
configureWebJobs?.Invoke(webJobsBuilder);
}, o => o.AllowPartialHostStartup = true,
(context, webJobsConfigBuilder) =>
{
if (!skipHostInitialization)
{
var webJobsBuilderContext = new WebJobsBuilderContext
{
Configuration = context.Configuration,
EnvironmentName = context.HostingEnvironment.EnvironmentName,
ApplicationRootPath = applicationHostOptions.ScriptPath
};
// Delay this call so we can call the customer's setup last.
context.Properties[DelayedConfigurationActionKey] = new Action<IWebJobsStartupTypeLocator>(locator =>
{
try
{
webJobsConfigBuilder.UseExternalConfigurationStartup(locator, webJobsBuilderContext, loggerFactory);
}
catch (Exception ex)
{
// Go directly to the environment; We have no valid configuration from the customer at this point.
string appInsightsConnStr = GetConfigurationValue(EnvironmentSettingNames.AppInsightsConnectionString);
string appInsightsAuthStr = GetConfigurationValue(EnvironmentSettingNames.AppInsightsAuthenticationString);
RecordAndThrowExternalStartupException("Error building configuration in an external startup class.", ex, loggerFactory, appInsightsConnStr, appInsightsAuthStr);
}
});
}
});
// Script host services - these services are scoped to a host instance, and when a new host
// is created, these services are recreated
builder.ConfigureServices(services =>
{
// Core WebJobs/Script Host services
services.AddSingleton<ScriptHost>();
// HTTP Worker
services.AddSingleton<IHttpWorkerProcessFactory, HttpWorkerProcessFactory>();
services.AddSingleton<IHttpWorkerChannelFactory, HttpWorkerChannelFactory>();
services.AddSingleton<IHttpWorkerService, DefaultHttpWorkerService>();
// Rpc Worker
services.AddSingleton<IJobHostRpcWorkerChannelManager, JobHostRpcWorkerChannelManager>();
services.AddSingleton<IRpcFunctionInvocationDispatcherLoadBalancer, RpcFunctionInvocationDispatcherLoadBalancer>();
//Worker Function Invocation dispatcher
services.AddSingleton<IFunctionInvocationDispatcherFactory, FunctionInvocationDispatcherFactory>();
services.AddSingleton<IScriptJobHost>(p => p.GetRequiredService<ScriptHost>());
services.AddSingleton<IJobHost>(p => p.GetRequiredService<ScriptHost>());
services.AddSingleton<IFunctionProvider, ProxyFunctionProvider>();
services.AddSingleton<IHostedService, WorkerConcurrencyManager>();
services.AddSingleton<ITypeLocator, ScriptTypeLocator>();
services.AddSingleton<ScriptSettingsManager>();
services.AddTransient<IExtensionsManager, ExtensionsManager>();
services.TryAddSingleton<IHttpRoutesManager, DefaultHttpRouteManager>();
services.TryAddSingleton<IMetricsLogger, MetricsLogger>();
services.AddTransient<IExtensionBundleContentProvider, ExtensionBundleContentProvider>();
// Script binding providers
services.TryAddEnumerable(ServiceDescriptor.Singleton<IScriptBindingProvider, WebJobsCoreScriptBindingProvider>());
services.TryAddEnumerable(ServiceDescriptor.Singleton<IScriptBindingProvider, CoreExtensionsScriptBindingProvider>());
services.TryAddEnumerable(ServiceDescriptor.Singleton<IScriptBindingProvider, GeneralScriptBindingProvider>());
// Configuration
services.AddSingleton<IOptions<ScriptApplicationHostOptions>>(new OptionsWrapper<ScriptApplicationHostOptions>(applicationHostOptions));
services.AddSingleton<IOptionsMonitor<ScriptApplicationHostOptions>>(new ScriptApplicationHostOptionsMonitor(applicationHostOptions));
services.ConfigureOptions<ScriptJobHostOptionsSetup>();
services.ConfigureOptions<JobHostFunctionTimeoutOptionsSetup>();
services.AddOptions<WorkerConcurrencyOptions>();
services.ConfigureOptions<HttpWorkerOptionsSetup>();
services.ConfigureOptions<ManagedDependencyOptionsSetup>();
services.AddOptions<FunctionResultAggregatorOptions>()
.Configure<IConfiguration>((o, c) =>
{
c.GetSection(ConfigurationSectionNames.JobHost)
.GetSection(ConfigurationSectionNames.Aggregator)
.Bind(o);
});
services.ConfigureOptions<ScaleOptionsSetup>();
services.AddSingleton<IFileLoggingStatusManager, FileLoggingStatusManager>();
if (applicationHostOptions.HasParentScope)
{
// Forward the host LanguageWorkerOptions to the Job Host.
var languageWorkerOptions = applicationHostOptions.RootServiceProvider.GetService<IOptionsMonitor<LanguageWorkerOptions>>();
services.AddSingleton(languageWorkerOptions);
services.AddSingleton<IOptions<LanguageWorkerOptions>>(s => new OptionsWrapper<LanguageWorkerOptions>(languageWorkerOptions.CurrentValue));
services.ConfigureOptions<JobHostLanguageWorkerOptionsSetup>();
}
else
{
services.ConfigureOptions<LanguageWorkerOptionsSetup>();
AddCommonServices(services);
}
if (SystemEnvironment.Instance.IsKubernetesManagedHosting())
{
services.AddSingleton<IDistributedLockManager, KubernetesDistributedLockManager>();
}
services.TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService, FunctionInvocationDispatcherShutdownManager>());
services.AddSingleton<IHostOptionsProvider, HostOptionsProvider>();
services.AddSingleton<IInstanceServicesProviderFactory, ScriptInstanceServicesProviderFactory>();
});
RegisterFileProvisioningService(builder);
return builder;
}