File: Builder\ServerRazorComponentsEndpointConventionBuilderExtensions.cs
Web Access
Project: src\src\Components\Server\src\Microsoft.AspNetCore.Components.Server.csproj (Microsoft.AspNetCore.Components.Server)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using Microsoft.AspNetCore.Components.Endpoints;
using Microsoft.AspNetCore.Components.Endpoints.Infrastructure;
using Microsoft.AspNetCore.Components.Server;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Primitives;
 
namespace Microsoft.AspNetCore.Builder;
 
/// <summary>
/// Interactive server specific endpoint conventions for razor component applications.
/// </summary>
public static class ServerRazorComponentsEndpointConventionBuilderExtensions
{
    /// <summary>
    /// Configures the application to support the <see cref="RenderMode.InteractiveServer"/> render mode.
    /// </summary>
    /// <returns>The <see cref="RazorComponentsEndpointConventionBuilder"/>.</returns>
    public static RazorComponentsEndpointConventionBuilder AddInteractiveServerRenderMode(this RazorComponentsEndpointConventionBuilder builder)
    {
        return AddInteractiveServerRenderMode(builder, (_) => { });
    }
 
    /// <summary>
    /// Maps the Blazor <see cref="Hub" /> to the default path.
    /// </summary>
    /// <param name="builder">The <see cref="RazorComponentsEndpointConventionBuilder"/>.</param>
    /// <param name="configure">A callback to configure server endpoint options.</param>
    /// <returns>The <see cref="ComponentEndpointConventionBuilder"/>.</returns>
    public static RazorComponentsEndpointConventionBuilder AddInteractiveServerRenderMode(
        this RazorComponentsEndpointConventionBuilder builder,
        Action<ServerComponentsEndpointOptions> configure)
    {
        ArgumentNullException.ThrowIfNull(builder);
        ArgumentNullException.ThrowIfNull(configure);
 
        var options = new ServerComponentsEndpointOptions();
        configure.Invoke(options);
 
        ComponentEndpointConventionBuilderHelper.AddRenderMode(builder, new InternalServerRenderMode(options));
 
        if ((options.ConfigureWebSocketAcceptContext is not null || !options.DisableWebSocketCompression) &&
            options.ContentSecurityFrameAncestorsPolicy != null)
        {
            builder.Add(b =>
            {
                for (var i = 0; i < b.Metadata.Count; i++)
                {
                    var metadata = b.Metadata[i];
                    if (metadata is ComponentTypeMetadata)
                    {
                        var original = b.RequestDelegate;
                        b.RequestDelegate = async context =>
                        {
                            var headers = context.Response.Headers;
                            headers.ContentSecurityPolicy = StringValues.Concat(headers.ContentSecurityPolicy, $"frame-ancestors {options.ContentSecurityFrameAncestorsPolicy}");
                            await original(context);
                        };
                    }
                }
            });
        }
 
        return builder;
    }
}