Skip to content

Commit

Permalink
Wire up conventions through MapStaticAssetEndpoints, use fallback oth…
Browse files Browse the repository at this point in the history
…erwise
  • Loading branch information
javiercn committed May 7, 2024
1 parent 421d380 commit cfc9bf1
Show file tree
Hide file tree
Showing 17 changed files with 117 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;

namespace Microsoft.AspNetCore.Components.Endpoints.Infrastructure;

Expand All @@ -19,5 +20,11 @@ public static void AddRenderMode(RazorComponentsEndpointConventionBuilder builde
{
builder.AddRenderMode(renderMode);
}

/// <summary>
/// This method is not recommended for use outside of the Blazor framework.
/// </summary>
/// <param name="builder"></param>
public static IEndpointRouteBuilder GetEndpointRouteBuilder(RazorComponentsEndpointConventionBuilder builder) => builder.EndpointRouteBuilder;
}

Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,20 @@ internal class RazorComponentEndpointDataSource<[DynamicallyAccessedMembers(Comp
public RazorComponentEndpointDataSource(
ComponentApplicationBuilder builder,
IEnumerable<RenderModeEndpointProvider> renderModeEndpointProviders,
IApplicationBuilder applicationBuilder,
IEndpointRouteBuilder endpointRouteBuilder,
RazorComponentEndpointFactory factory,
HotReloadService? hotReloadService = null)
{
_builder = builder;
_applicationBuilder = applicationBuilder;
_applicationBuilder = endpointRouteBuilder.CreateApplicationBuilder();
_renderModeEndpointProviders = renderModeEndpointProviders.ToArray();
_factory = factory;
_hotReloadService = hotReloadService;
HotReloadService.ClearCacheEvent += OnHotReloadClearCache;
DefaultBuilder = new RazorComponentsEndpointConventionBuilder(
_lock,
builder,
endpointRouteBuilder,
_options,
_conventions,
_finallyConventions);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ internal class RazorComponentEndpointDataSourceFactory
var builder = ComponentApplicationBuilder.GetBuilder<TRootComponent>() ??
DefaultRazorComponentApplication<TRootComponent>.Instance.GetBuilder();

return new RazorComponentEndpointDataSource<TRootComponent>(builder, _providers, endpoints.CreateApplicationBuilder(), _factory, _hotReloadService);
return new RazorComponentEndpointDataSource<TRootComponent>(builder, _providers, endpoints, _factory, _hotReloadService);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Discovery;
using Microsoft.AspNetCore.Components.Endpoints;
using Microsoft.AspNetCore.Routing;

namespace Microsoft.AspNetCore.Builder;

Expand All @@ -14,19 +15,22 @@ public sealed class RazorComponentsEndpointConventionBuilder : IEndpointConventi
{
private readonly object _lock;
private readonly ComponentApplicationBuilder _builder;
private readonly IEndpointRouteBuilder _endpointRouteBuilder;
private readonly RazorComponentDataSourceOptions _options;
private readonly List<Action<EndpointBuilder>> _conventions;
private readonly List<Action<EndpointBuilder>> _finallyConventions;

internal RazorComponentsEndpointConventionBuilder(
object @lock,
ComponentApplicationBuilder builder,
IEndpointRouteBuilder endpointRouteBuilder,
RazorComponentDataSourceOptions options,
List<Action<EndpointBuilder>> conventions,
List<Action<EndpointBuilder>> finallyConventions)
{
_lock = @lock;
_builder = builder;
_endpointRouteBuilder = endpointRouteBuilder;
_options = options;
_conventions = conventions;
_finallyConventions = finallyConventions;
Expand All @@ -37,6 +41,8 @@ public sealed class RazorComponentsEndpointConventionBuilder : IEndpointConventi
/// </summary>
internal ComponentApplicationBuilder ApplicationBuilder => _builder;

internal IEndpointRouteBuilder EndpointRouteBuilder => _endpointRouteBuilder;

/// <inheritdoc/>
public void Add(Action<EndpointBuilder> convention)
{
Expand Down Expand Up @@ -64,6 +70,6 @@ public void Finally(Action<EndpointBuilder> finallyConvention)
internal void AddRenderMode(IComponentRenderMode renderMode)
{
_options.ConfiguredRenderModes.Add(renderMode);
}
}
}

1 change: 1 addition & 0 deletions src/Components/Endpoints/src/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#nullable enable
Microsoft.AspNetCore.Components.Routing.RazorComponentsEndpointHttpContextExtensions
static Microsoft.AspNetCore.Components.Endpoints.Infrastructure.ComponentEndpointConventionBuilderHelper.GetEndpointRouteBuilder(Microsoft.AspNetCore.Builder.RazorComponentsEndpointConventionBuilder! builder) -> Microsoft.AspNetCore.Routing.IEndpointRouteBuilder!
static Microsoft.AspNetCore.Components.Routing.RazorComponentsEndpointHttpContextExtensions.AcceptsInteractiveRouting(this Microsoft.AspNetCore.Http.HttpContext! context) -> bool
16 changes: 15 additions & 1 deletion src/Components/Endpoints/test/HotReloadServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ private IServiceProvider CreateServices(params Type[] types)
var result = new RazorComponentEndpointDataSource<TComponent>(
builder,
new[] { new MockEndpointProvider() },
new ApplicationBuilder(services),
new TestEndpointRouteBuilder(services),
new RazorComponentEndpointFactory(),
new HotReloadService() { MetadataUpdateSupported = true });

Expand Down Expand Up @@ -256,4 +256,18 @@ public override IEnumerable<RouteEndpointBuilder> GetEndpointBuilders(IComponent

public override bool Supports(IComponentRenderMode renderMode) => true;
}

private class TestEndpointRouteBuilder : IEndpointRouteBuilder
{
private IServiceProvider _serviceProvider;
private List<EndpointDataSource> _dataSources = new();

public TestEndpointRouteBuilder(IServiceProvider serviceProvider) => _serviceProvider = serviceProvider;

public IServiceProvider ServiceProvider => _serviceProvider;

public ICollection<EndpointDataSource> DataSources => _dataSources;

public IApplicationBuilder CreateApplicationBuilder() => new ApplicationBuilder(_serviceProvider);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ private IServiceProvider CreateServices(params Type[] types)
var result = new RazorComponentEndpointDataSource<TComponent>(
builder ?? DefaultRazorComponentApplication<TComponent>.Instance.GetBuilder(),
services?.GetService<IEnumerable<RenderModeEndpointProvider>>() ?? Enumerable.Empty<RenderModeEndpointProvider>(),
new ApplicationBuilder(services ?? new ServiceCollection().BuildServiceProvider()),
new TestEndpointRouteBuilder(services ?? new ServiceCollection().BuildServiceProvider()),
new RazorComponentEndpointFactory(),
new HotReloadService() { MetadataUpdateSupported = true });

Expand Down Expand Up @@ -277,6 +277,20 @@ public override IEnumerable<RouteEndpointBuilder> GetEndpointBuilders(IComponent

public override bool Supports(IComponentRenderMode renderMode) => renderMode is InteractiveWebAssemblyRenderMode or InteractiveAutoRenderMode;
}

private class TestEndpointRouteBuilder : IEndpointRouteBuilder
{
private IServiceProvider _serviceProvider;
private List<EndpointDataSource> _dataSources = new();

public TestEndpointRouteBuilder(IServiceProvider serviceProvider) => _serviceProvider = serviceProvider;

public IServiceProvider ServiceProvider => _serviceProvider;

public ICollection<EndpointDataSource> DataSources => _dataSources;

public IApplicationBuilder CreateApplicationBuilder() => new ApplicationBuilder(_serviceProvider);
}
}

public class App : IComponent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,13 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

app.UseHttpsRedirection();

//app.UseBlazorFrameworkFiles();

app.UseRouting();

//app.UseStaticFiles();

app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.MapStaticAssetEndpoints()
.AddBlazorWebAssemblyConventions();
endpoints.MapStaticAssetEndpoints();
endpoints.MapFallbackToPage("/_Host");
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,5 @@ public sealed class WebAssemblyComponentsEndpointOptions
/// </summary>
public string? StaticAssetsManifestName { get; set; }

internal bool ConventionsApplied { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
using Microsoft.AspNetCore.Components.Endpoints.Infrastructure;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Server;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.StaticAssets;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.Linq;

namespace Microsoft.AspNetCore.Builder;
Expand Down Expand Up @@ -45,6 +49,36 @@ public static class WebAssemblyRazorComponentsEndpointConventionBuilderExtension
}

ComponentEndpointConventionBuilderHelper.AddRenderMode(builder, new WebAssemblyRenderModeWithOptions(options));

var endpointBuilder = ComponentEndpointConventionBuilderHelper.GetEndpointRouteBuilder(builder);
var environment = endpointBuilder.ServiceProvider.GetRequiredService<IHostEnvironment>();

// If the static assets data source for the given manifest name is already added, then just wire-up the Blazor WebAssembly conventions.
// MapStaticWebAssetEndpoints is idempotent and will not add the data source if it already exists.
var staticAssetsManifestName = options.StaticAssetsManifestName ?? $"{environment.ApplicationName}.staticwebassets.endpoints.json";
if (HasStaticAssetDataSource(endpointBuilder, staticAssetsManifestName))
{
options.ConventionsApplied = true;
endpointBuilder.MapStaticAssetEndpoints(staticAssetsManifestName)
.AddBlazorWebAssemblyConventions();

return builder;
}

return builder;
}

private static bool HasStaticAssetDataSource(IEndpointRouteBuilder endpointRouteBuilder, string? staticAssetsManifestName)
{
foreach (var ds in endpointRouteBuilder.DataSources)
{
if (ds is StaticAssetsEndpointDataSource staticAssetsDataSource &&
string.Equals(staticAssetsDataSource.ManifestName, staticAssetsManifestName, StringComparison.Ordinal))
{
return true;
}
}

return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ public static class ComponentsWebAssemblyStaticAssetsEndpointConventionBuilderEx
/// Configures additional static web asset extensions logic for Blazor WebAssembly.
/// </summary>
/// <param name="builder"></param>
public static void AddBlazorWebAssemblyConventions(this StaticAssetsEndpointConventionBuilder builder)
internal static void AddBlazorWebAssemblyConventions(this StaticAssetsEndpointConventionBuilder builder)
{
builder.Add(endpoint =>
{
if (endpoint is RouteEndpointBuilder { RoutePattern.RawText: { } pattern } && pattern.StartsWith("/_framework/", StringComparison.Ordinal) &&
!pattern.StartsWith("/_framework/blazor.server.js", StringComparison.Ordinal) && !pattern.StartsWith("/_framework/blazor.web.js", StringComparison.Ordinal))
if (endpoint is RouteEndpointBuilder { RoutePattern.RawText: { } pattern } && pattern.Contains("/_framework/", StringComparison.Ordinal) &&
!pattern.Contains("/_framework/blazor.server.js", StringComparison.Ordinal) && !pattern.Contains("/_framework/blazor.web.js", StringComparison.Ordinal))
{
WrapEndpoint(endpoint);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@ Microsoft.AspNetCore.Components.WebAssembly.Server.WebAssemblyComponentsEndpoint
Microsoft.AspNetCore.Components.WebAssembly.Server.WebAssemblyComponentsEndpointOptions.ServeMultithreadingHeaders.set -> void
Microsoft.AspNetCore.Components.WebAssembly.Server.WebAssemblyComponentsEndpointOptions.StaticAssetsManifestName.get -> string?
Microsoft.AspNetCore.Components.WebAssembly.Server.WebAssemblyComponentsEndpointOptions.StaticAssetsManifestName.set -> void
static Microsoft.AspNetCore.Components.WebAssembly.Server.ComponentsWebAssemblyStaticAssetsEndpointConventionBuilderExtensions.AddBlazorWebAssemblyConventions(this Microsoft.AspNetCore.StaticAssets.StaticAssetsEndpointConventionBuilder! builder) -> void
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Endpoints.Infrastructure;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Server;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection.Extensions;
Expand Down Expand Up @@ -37,25 +36,18 @@ public override IEnumerable<RouteEndpointBuilder> GetEndpointBuilders(IComponent
{
if (renderMode is not WebAssemblyRenderModeWithOptions wasmWithOptions)
{
if (renderMode is InteractiveWebAssemblyRenderMode)
{
throw new InvalidOperationException("Invalid render mode. Use AddInteractiveWebAssemblyRenderMode(Action<WebAssemblyComponentsEndpointOptions>) to configure the WebAssembly render mode.");
}

return Array.Empty<RouteEndpointBuilder>();
return renderMode is InteractiveWebAssemblyRenderMode
? throw new InvalidOperationException("Invalid render mode. Use AddInteractiveWebAssemblyRenderMode(Action<WebAssemblyComponentsEndpointOptions>) to configure the WebAssembly render mode.")
: (IEnumerable<RouteEndpointBuilder>)Array.Empty<RouteEndpointBuilder>();
}

if (applicationBuilder.Properties.TryGetValue("__EndpointRouteBuilder", out var value) && value is IEndpointRouteBuilder endpointRouteBuilder)
if (wasmWithOptions is { EndpointOptions.ConventionsApplied: true })
{
// Map static asset endpoints is idempotent, if it was already called with a given manifest name, it will return the existing builder.
endpointRouteBuilder.MapStaticAssetEndpoints(wasmWithOptions.EndpointOptions?.StaticAssetsManifestName)
.AddBlazorWebAssemblyConventions();

return []; // No need to add additional endpoints to the DS, they are already added
}
else
{
endpointRouteBuilder = new EndpointRouteBuilder(services, applicationBuilder);
// In case the app didn't call MapStaticAssetEndpoints, use the 8.0 approach to map the assets.
var endpointRouteBuilder = new EndpointRouteBuilder(services, applicationBuilder);
var pathPrefix = wasmWithOptions.EndpointOptions?.PathPrefix;

applicationBuilder.UseBlazorFrameworkFiles(pathPrefix ?? default);
Expand All @@ -69,12 +61,14 @@ public override IEnumerable<RouteEndpointBuilder> GetEndpointBuilders(IComponent
return app(context);
});

return ((EndpointRouteBuilder)endpointRouteBuilder).GetEndpoints();
return endpointRouteBuilder.GetEndpoints();
}
}

public override bool Supports(IComponentRenderMode renderMode)
=> renderMode is InteractiveWebAssemblyRenderMode or InteractiveAutoRenderMode;
{
return renderMode is InteractiveWebAssemblyRenderMode or InteractiveAutoRenderMode;
}

private class EndpointRouteBuilder : IEndpointRouteBuilder
{
Expand All @@ -88,7 +82,7 @@ public EndpointRouteBuilder(IServiceProvider serviceProvider, IApplicationBuilde

public IServiceProvider ServiceProvider { get; }

public ICollection<EndpointDataSource> DataSources { get; } = new List<EndpointDataSource>() { };
public ICollection<EndpointDataSource> DataSources { get; } = [];

public IApplicationBuilder CreateApplicationBuilder()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Components.TestServer.RazorComponents.Pages.Forms;
using Components.TestServer.Services;
using Microsoft.AspNetCore.Components.Server.Circuits;
using Microsoft.AspNetCore.Components.WebAssembly.Server;
using Microsoft.AspNetCore.Mvc;

namespace TestServer;
Expand Down Expand Up @@ -64,7 +65,6 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseExceptionHandler("/Error", createScopeForErrors: true);
}
app.UseStaticFiles();
app.UseRouting();
UseFakeAuthState(app);
app.UseAntiforgery();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.Map("/subdir", app =>
{
app.UseStaticFiles();
app.UseRouting();
app.UseAntiforgery();
app.UseEndpoints(endpoints =>
Expand Down
5 changes: 5 additions & 0 deletions src/StaticAssets/src/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,9 @@
Microsoft.AspNetCore.StaticAssets.StaticAssetsEndpointConventionBuilder
Microsoft.AspNetCore.StaticAssets.StaticAssetsEndpointConventionBuilder.Add(System.Action<Microsoft.AspNetCore.Builder.EndpointBuilder!>! convention) -> void
Microsoft.AspNetCore.StaticAssets.StaticAssetsEndpointConventionBuilder.Finally(System.Action<Microsoft.AspNetCore.Builder.EndpointBuilder!>! convention) -> void
Microsoft.AspNetCore.StaticAssets.StaticAssetsEndpointDataSource
Microsoft.AspNetCore.StaticAssets.StaticAssetsEndpointDataSource.DefaultBuilder.get -> Microsoft.AspNetCore.StaticAssets.StaticAssetsEndpointConventionBuilder!
Microsoft.AspNetCore.StaticAssets.StaticAssetsEndpointDataSource.ManifestName.get -> string!
override Microsoft.AspNetCore.StaticAssets.StaticAssetsEndpointDataSource.Endpoints.get -> System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Http.Endpoint!>!
override Microsoft.AspNetCore.StaticAssets.StaticAssetsEndpointDataSource.GetChangeToken() -> Microsoft.Extensions.Primitives.IChangeToken!
static Microsoft.AspNetCore.Builder.StaticAssetsEndpointRouteBuilderExtensions.MapStaticAssetEndpoints(this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder! endpoints, string? staticAssetsManifestName = null) -> Microsoft.AspNetCore.StaticAssets.StaticAssetsEndpointConventionBuilder!

0 comments on commit cfc9bf1

Please sign in to comment.