| File: Program.cs | Web Access |
| Project: src\playground\BlazorHosted\BlazorHosted.Server\BlazorHosted.csproj (BlazorHosted) |
using BlazorHosted.Components; var builder = WebApplication.CreateBuilder(args); builder.AddServiceDefaults(); // Filter out OTLP proxy traffic from tracing to prevent a feedback loop: // YARP forwards /_otlp/* requests to the dashboard, and without filtering, // those forwarding requests would themselves be traced and exported — creating // recursive telemetry entries in the dashboard. builder.Services.PostConfigure<OpenTelemetry.Instrumentation.AspNetCore.AspNetCoreTraceInstrumentationOptions>(options => { var previous = options.Filter; options.Filter = context => { var path = context.Request.Path.Value; return (previous is null || previous(context)) && (path is null || !path.Contains("/_otlp/", StringComparison.Ordinal)); }; }); builder.Services.PostConfigure<OpenTelemetry.Instrumentation.Http.HttpClientTraceInstrumentationOptions>(options => { var previous = options.FilterHttpRequestMessage; options.FilterHttpRequestMessage = request => (previous is null || previous(request)) && (request.RequestUri is null || !request.RequestUri.AbsolutePath.StartsWith("/v1/", StringComparison.Ordinal)); }); builder.Services.AddRazorComponents() .AddInteractiveWebAssemblyComponents(); // YARP for proxying service calls from the WASM client builder.Services.AddReverseProxy() .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy")) .AddServiceDiscoveryDestinationResolver(); // Register the same named HttpClient used by the WASM client's Weather component. // During prerendering the component runs on the server, so the server needs // this registration to resolve "https+http://weatherapi" via service discovery. builder.Services.AddHttpClient("weatherapi", client => { client.BaseAddress = new Uri("https+http://weatherapi"); }); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseWebAssemblyDebugging(); } else { app.UseExceptionHandler("/Error", createScopeForErrors: true); app.UseHsts(); } // Only redirect document navigations (browser URL bar / top-level navigation) from HTTP // to HTTPS. The Sec-Fetch-Dest header distinguishes navigations from subresource loads // and API fetches. This ensures the WASM client loads on HTTPS when available, making // OTLP and service fetch requests same-origin, without redirecting programmatic requests // that might legitimately target the HTTP endpoint. // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Sec-Fetch-Dest app.UseWhen( context => string.Equals( context.Request.Headers["Sec-Fetch-Dest"].ToString(), "document", StringComparison.OrdinalIgnoreCase), branch => branch.UseHttpsRedirection()); app.MapDefaultEndpoints(); // Serve the Blazor WASM client configuration endpoint. // The Aspire host sets Client__ConfigEndpointPath and Client__ConfigResponse // as environment variables; the server reads them and serves the JSON response. var configEndpointPath = app.Configuration["Client:ConfigEndpointPath"]; var configResponse = app.Configuration["Client:ConfigResponse"]; if (!string.IsNullOrEmpty(configEndpointPath) && !string.IsNullOrEmpty(configResponse)) { app.MapGet(configEndpointPath, () => Results.Content(configResponse, "application/json")); } app.UseAntiforgery(); app.MapStaticAssets(); app.MapReverseProxy(); app.MapRazorComponents<App>() .AddInteractiveWebAssemblyRenderMode() .AddAdditionalAssemblies(typeof(BlazorHosted.Client._Imports).Assembly); app.Run();