in src/Service/Startup.cs [405:549]
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, RuntimeConfigProvider runtimeConfigProvider, IHostApplicationLifetime hostLifetime)
{
bool isRuntimeReady = false;
if (runtimeConfigProvider.TryGetConfig(out RuntimeConfig? runtimeConfig))
{
// Configure Application Insights Telemetry
ConfigureApplicationInsightsTelemetry(app, runtimeConfig);
ConfigureOpenTelemetry(runtimeConfig);
// Config provided before starting the engine.
isRuntimeReady = PerformOnConfigChangeAsync(app).Result;
if (!isRuntimeReady)
{
// Exiting if config provided is Invalid.
if (_logger is not null)
{
_logger.LogError(
message: "Could not initialize the engine with the runtime config file: {configFilePath}",
runtimeConfigProvider.ConfigFilePath);
}
hostLifetime.StopApplication();
}
}
else
{
// Config provided during runtime.
runtimeConfigProvider.IsLateConfigured = true;
runtimeConfigProvider.RuntimeConfigLoadedHandlers.Add(async (sender, newConfig) =>
{
isRuntimeReady = await PerformOnConfigChangeAsync(app);
return isRuntimeReady;
});
}
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
if (!Program.IsHttpsRedirectionDisabled)
{
app.UseHttpsRedirection();
}
// URL Rewrite middleware MUST be called prior to UseRouting().
// https://andrewlock.net/understanding-pathbase-in-aspnetcore/#placing-usepathbase-in-the-correct-location
app.UseCorrelationIdMiddleware();
app.UsePathRewriteMiddleware();
// SwaggerUI visualization of the OpenAPI description document is only available
// in developer mode in alignment with the restriction placed on ChilliCream's BananaCakePop IDE.
// Consequently, SwaggerUI is not presented in a StaticWebApps (late-bound config) environment.
if (IsUIEnabled(runtimeConfig, env))
{
app.UseSwaggerUI(c =>
{
c.ConfigObject.Urls = new SwaggerEndpointMapper(app.ApplicationServices.GetService<RuntimeConfigProvider?>());
});
}
app.UseRouting();
// Adding CORS Middleware
if (runtimeConfig is not null && runtimeConfig.Runtime?.Host?.Cors is not null)
{
app.UseCors(CORSPolicyBuilder =>
{
CorsOptions corsConfig = runtimeConfig.Runtime.Host.Cors;
ConfigureCors(CORSPolicyBuilder, corsConfig);
});
}
app.Use(async (context, next) =>
{
bool isHealthCheckRequest = context.Request.Path == "/" && context.Request.Method == HttpMethod.Get.Method;
bool isSettingConfig = context.Request.Path.StartsWithSegments("/configuration")
&& context.Request.Method == HttpMethod.Post.Method;
if (isRuntimeReady || isHealthCheckRequest)
{
await next.Invoke();
}
else if (isSettingConfig)
{
if (isRuntimeReady)
{
context.Response.StatusCode = StatusCodes.Status409Conflict;
}
else
{
await next.Invoke();
}
}
else
{
context.Response.StatusCode = StatusCodes.Status503ServiceUnavailable;
}
});
app.UseAuthentication();
app.UseClientRoleHeaderAuthenticationMiddleware();
app.UseAuthorization();
// Authorization Engine middleware enforces that all requests (including introspection)
// include proper auth headers.
// - {Authorization header + Client role header for JWT}
// - {X-MS-CLIENT-PRINCIPAL + Client role header for EasyAuth}
// When enabled, the middleware will prevent Banana Cake Pop(GraphQL client) from loading
// without proper authorization headers.
app.UseClientRoleHeaderAuthorizationMiddleware();
IRequestExecutorResolver requestExecutorResolver = app.ApplicationServices.GetRequiredService<IRequestExecutorResolver>();
_hotReloadEventHandler.Subscribe("GRAPHQL_SCHEMA_EVICTION_ON_CONFIG_CHANGED", (sender, args) => EvictGraphQLSchema(requestExecutorResolver));
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapGraphQL(GraphQLRuntimeOptions.DEFAULT_PATH).WithOptions(new GraphQLServerOptions
{
Tool = {
// Determines if accessing the endpoint from a browser
// will load the GraphQL Banana Cake Pop IDE.
Enable = IsUIEnabled(runtimeConfig, env)
}
});
// In development mode, BCP is enabled at /graphql endpoint by default.
// Need to disable mapping BCP explicitly as well to avoid ability to query
// at an additional endpoint: /graphql/ui.
endpoints.MapBananaCakePop().WithOptions(new GraphQLToolOptions
{
Enable = false
});
endpoints.MapHealthChecks("/", new HealthCheckOptions
{
ResponseWriter = app.ApplicationServices.GetRequiredService<BasicHealthReportResponseWriter>().WriteResponse
});
});
}