Skip to content

Commit 4802de1

Browse files
[Blazor] Manual reflection based page discovery (#49757)
* Support configuring hub options * tmp * make build pass * Remove unnecessary APIs * Remove more APIs * Apply API review feedback * More feedback, fix buid, etc. * API updates and fixes * Add WasmMinimal * Undo API change * Fix build * Fix build * API changes * PR feedback --------- Co-authored-by: Mackinnon Buck <mackinnon.buck@gmail.com>
1 parent fb93028 commit 4802de1

37 files changed

+302
-415
lines changed

src/Components/ComponentsNoDeps.slnf

+3-2
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,13 @@
4747
"src\\Components\\benchmarkapps\\Wasm.Performance\\TestApp\\Wasm.Performance.TestApp.csproj",
4848
"src\\Components\\test\\E2ETest\\Microsoft.AspNetCore.Components.E2ETests.csproj",
4949
"src\\Components\\test\\testassets\\BasicTestApp\\BasicTestApp.csproj",
50+
"src\\Components\\test\\testassets\\Components.TestServer\\Components.TestServer.csproj",
51+
"src\\Components\\test\\testassets\\Components.WasmMinimal\\Components.WasmMinimal.csproj",
5052
"src\\Components\\test\\testassets\\ComponentsApp.App\\ComponentsApp.App.csproj",
5153
"src\\Components\\test\\testassets\\ComponentsApp.Server\\ComponentsApp.Server.csproj",
5254
"src\\Components\\test\\testassets\\GlobalizationWasmApp\\GlobalizationWasmApp.csproj",
5355
"src\\Components\\test\\testassets\\LazyTestContentPackage\\LazyTestContentPackage.csproj",
54-
"src\\Components\\test\\testassets\\TestContentPackage\\TestContentPackage.csproj",
55-
"src\\Components\\test\\testassets\\Components.TestServer\\Components.TestServer.csproj"
56+
"src\\Components\\test\\testassets\\TestContentPackage\\TestContentPackage.csproj"
5657
]
5758
}
5859
}

src/Components/Endpoints/src/Builder/ComponentTypeMetadata.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Components.Endpoints;
99
/// <summary>
1010
/// Metadata that represents the component associated with an endpoint.
1111
/// </summary>
12-
public class ComponentTypeMetadata
12+
public sealed class ComponentTypeMetadata
1313
{
1414
/// <summary>
1515
/// Initializes a new instance of <see cref="ComponentTypeMetadata"/>.

src/Components/Endpoints/src/Builder/RazorComponentApplicationAttribute.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace Microsoft.AspNetCore.Components.Infrastructure;
1010
/// application.
1111
/// </summary>
1212
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)]
13-
public abstract class RazorComponentApplicationAttribute : Attribute, IRazorComponentApplication
13+
internal abstract class RazorComponentApplicationAttribute : Attribute, IRazorComponentApplication
1414
{
1515
/// <summary>
1616
/// Creates a builder that can be used to customize the definition of the application.

src/Components/Endpoints/src/Builder/RazorComponentDataSourceOptions.cs

+17-11
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using Microsoft.AspNetCore.Builder;
5+
using Microsoft.AspNetCore.Components.Web;
56

67
namespace Microsoft.AspNetCore.Components.Endpoints;
78

@@ -10,17 +11,22 @@ namespace Microsoft.AspNetCore.Components.Endpoints;
1011
/// given <see cref="RazorComponentsEndpointRouteBuilderExtensions.MapRazorComponents{TRootComponent}(Microsoft.AspNetCore.Routing.IEndpointRouteBuilder)"/>
1112
/// invocation.
1213
/// </summary>
13-
public class RazorComponentDataSourceOptions
14+
internal class RazorComponentDataSourceOptions
1415
{
15-
/// <summary>
16-
/// Gets or sets whether to automatically wire up the necessary endpoints
17-
/// based on the declared render modes of the components that are
18-
/// part of this set of endpoints.
19-
/// </summary>
20-
/// <remarks>
21-
/// The default value is <c>true</c>.
22-
/// </remarks>
23-
public bool UseDeclaredRenderModes { get; set; } = true;
16+
internal static readonly EqualityComparer<IComponentRenderMode> RenderModeComparer = EqualityComparer<IComponentRenderMode>
17+
.Create(
18+
equals: (x, y) => (x,y) switch
19+
{
20+
(ServerRenderMode, ServerRenderMode) => true,
21+
(WebAssemblyRenderMode, WebAssemblyRenderMode) => true,
22+
_ => false,
23+
},
24+
getHashCode: obj => obj switch
25+
{
26+
ServerRenderMode => 1,
27+
WebAssemblyRenderMode => 2,
28+
_ => throw new InvalidOperationException($"Unknown render mode: {obj}"),
29+
});
2430

25-
internal IList<IComponentRenderMode> ConfiguredRenderModes { get; } = new List<IComponentRenderMode>();
31+
internal ISet<IComponentRenderMode> ConfiguredRenderModes { get; } = new HashSet<IComponentRenderMode>(RenderModeComparer);
2632
}

src/Components/Endpoints/src/Builder/RazorComponentEndpointDataSource.cs

+3-9
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Linq;
77
using Microsoft.AspNetCore.Builder;
88
using Microsoft.AspNetCore.Components.Discovery;
9+
using Microsoft.AspNetCore.Components.Endpoints.Infrastructure;
910
using Microsoft.AspNetCore.Http;
1011
using Microsoft.AspNetCore.Routing;
1112
using Microsoft.Extensions.Primitives;
@@ -39,7 +40,7 @@ public RazorComponentEndpointDataSource(
3940
_applicationBuilder = applicationBuilder;
4041
_renderModeEndpointProviders = renderModeEndpointProviders.ToArray();
4142
_factory = factory;
42-
DefaultBuilder = new RazorComponentEndpointConventionBuilder(
43+
DefaultBuilder = new RazorComponentsEndpointConventionBuilder(
4344
_lock,
4445
builder,
4546
_options,
@@ -50,7 +51,7 @@ public RazorComponentEndpointDataSource(
5051
_changeToken = new CancellationChangeToken(_cancellationTokenSource.Token);
5152
}
5253

53-
internal RazorComponentEndpointConventionBuilder DefaultBuilder { get; }
54+
internal RazorComponentsEndpointConventionBuilder DefaultBuilder { get; }
5455

5556
public override IReadOnlyList<Endpoint> Endpoints
5657
{
@@ -98,13 +99,6 @@ private void UpdateEndpoints()
9899

99100
ICollection<IComponentRenderMode> renderModes = Options.ConfiguredRenderModes;
100101

101-
if (Options.UseDeclaredRenderModes)
102-
{
103-
var componentRenderModes = context.GetDeclaredRenderModesByDiscoveredComponents();
104-
componentRenderModes.UnionWith(Options.ConfiguredRenderModes);
105-
renderModes = componentRenderModes;
106-
}
107-
108102
foreach (var renderMode in renderModes)
109103
{
110104
var found = false;

src/Components/Endpoints/src/Builder/RazorComponentEndpointDataSourceFactory.cs

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Diagnostics.CodeAnalysis;
55
using Microsoft.AspNetCore.Components.Discovery;
66
using Microsoft.AspNetCore.Components.Endpoints;
7+
using Microsoft.AspNetCore.Components.Endpoints.Infrastructure;
78
using Microsoft.AspNetCore.Routing;
89
using static Microsoft.AspNetCore.Internal.LinkerFlags;
910

Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using Microsoft.AspNetCore.Components;
45
using Microsoft.AspNetCore.Components.Discovery;
56
using Microsoft.AspNetCore.Components.Endpoints;
67
using Microsoft.AspNetCore.Components.Web;
@@ -10,18 +11,15 @@ namespace Microsoft.AspNetCore.Builder;
1011
/// <summary>
1112
/// Builds conventions that will be used for customization of <see cref="EndpointBuilder"/> instances.
1213
/// </summary>
13-
14-
// TODO: This will have APIs to add and remove entire assemblies from the list of considered endpoints
15-
// as well as adding/removing individual pages as endpoints.
16-
public class RazorComponentEndpointConventionBuilder : IEndpointConventionBuilder
14+
public sealed class RazorComponentsEndpointConventionBuilder : IEndpointConventionBuilder
1715
{
1816
private readonly object _lock;
1917
private readonly ComponentApplicationBuilder _builder;
2018
private readonly RazorComponentDataSourceOptions _options;
2119
private readonly List<Action<EndpointBuilder>> _conventions;
2220
private readonly List<Action<EndpointBuilder>> _finallyConventions;
2321

24-
internal RazorComponentEndpointConventionBuilder(
22+
internal RazorComponentsEndpointConventionBuilder(
2523
object @lock,
2624
ComponentApplicationBuilder builder,
2725
RazorComponentDataSourceOptions options,
@@ -38,43 +36,14 @@ internal RazorComponentEndpointConventionBuilder(
3836
/// <summary>
3937
/// Gets the <see cref="ComponentApplicationBuilder"/> that is used to build the endpoints.
4038
/// </summary>
41-
public ComponentApplicationBuilder ApplicationBuilder => _builder;
42-
43-
/// <summary>
44-
/// Configures the <see cref="RenderMode.WebAssembly"/> for this application.
45-
/// </summary>
46-
/// <returns>The <see cref="RazorComponentEndpointConventionBuilder"/>.</returns>
47-
public RazorComponentEndpointConventionBuilder AddWebAssemblyRenderMode()
48-
{
49-
for (var i = 0; i < _options.ConfiguredRenderModes.Count; i++)
50-
{
51-
var mode = _options.ConfiguredRenderModes[i];
52-
if (mode is WebAssemblyRenderMode)
53-
{
54-
return this;
55-
}
56-
}
57-
58-
_options.ConfiguredRenderModes.Add(RenderMode.WebAssembly);
59-
60-
return this;
61-
}
39+
internal ComponentApplicationBuilder ApplicationBuilder => _builder;
6240

6341
/// <summary>
6442
/// Configures the <see cref="RenderMode.Server"/> for this application.
6543
/// </summary>
66-
/// <returns>The <see cref="RazorComponentEndpointConventionBuilder"/>.</returns>
67-
public RazorComponentEndpointConventionBuilder AddServerRenderMode()
44+
/// <returns>The <see cref="RazorComponentsEndpointConventionBuilder"/>.</returns>
45+
public RazorComponentsEndpointConventionBuilder AddServerRenderMode()
6846
{
69-
for (var i = 0; i < _options.ConfiguredRenderModes.Count; i++)
70-
{
71-
var mode = _options.ConfiguredRenderModes[i];
72-
if (mode is ServerRenderMode)
73-
{
74-
return this;
75-
}
76-
}
77-
7847
_options.ConfiguredRenderModes.Add(RenderMode.Server);
7948

8049
return this;
@@ -103,4 +72,13 @@ public void Finally(Action<EndpointBuilder> finallyConvention)
10372
_finallyConventions.Add(finallyConvention);
10473
}
10574
}
75+
76+
/// <summary>
77+
/// Adds the given <paramref name="renderMode"/> to the list of configured render modes if not present.
78+
/// </summary>
79+
/// <param name="renderMode">The <see cref="IComponentRenderMode"/> to add.</param>
80+
public void AddRenderMode(IComponentRenderMode renderMode)
81+
{
82+
_options.ConfiguredRenderModes.Add(renderMode);
83+
}
10684
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Reflection;
5+
6+
namespace Microsoft.AspNetCore.Builder;
7+
8+
/// <summary>
9+
/// Configures which assemblies are part of the given Razor Component Application.
10+
/// </summary>
11+
public static class RazorComponentsEndpointConventionBuilderExtensions
12+
{
13+
/// <summary>
14+
/// Adds the given additional assemblies to the component application.
15+
/// </summary>
16+
/// <param name="builder">The <see cref="RazorComponentsEndpointConventionBuilder"/>.</param>"/>
17+
/// <param name="assemblies">The <see cref="Assembly"/> instances to add.</param>
18+
/// <returns>The <see cref="RazorComponentsEndpointConventionBuilder"/>.</returns>
19+
/// <remarks>
20+
/// The provided assemblies will be scanned for pages that will be mapped as endpoints.
21+
/// </remarks>
22+
public static RazorComponentsEndpointConventionBuilder AddAdditionalAssemblies(
23+
this RazorComponentsEndpointConventionBuilder builder,
24+
params Assembly[] assemblies)
25+
{
26+
ArgumentNullException.ThrowIfNull(builder);
27+
ArgumentNullException.ThrowIfNull(assemblies);
28+
29+
foreach (var assembly in assemblies)
30+
{
31+
builder.ApplicationBuilder.AddAssembly(assembly);
32+
}
33+
return builder;
34+
}
35+
}

src/Components/Endpoints/src/Builder/RazorComponentsEndpointRouteBuilderExtensions.cs

+6-5
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,17 @@
1515
namespace Microsoft.AspNetCore.Builder;
1616

1717
/// <summary>
18-
///
18+
/// Extensions to <see cref="IEndpointRouteBuilder"/> for razor component applications.
1919
/// </summary>
2020
public static class RazorComponentsEndpointRouteBuilderExtensions
2121
{
2222
/// <summary>
23-
///
23+
/// Maps the page components defined in the specified <typeparamref name="TRootComponent"/> to the given assembly
24+
/// and renders the component specified by <typeparamref name="TRootComponent"/> when the route matches.
2425
/// </summary>
25-
/// <param name="endpoints"></param>
26-
/// <returns></returns>
27-
public static RazorComponentEndpointConventionBuilder MapRazorComponents<[DynamicallyAccessedMembers(Component)] TRootComponent>(this IEndpointRouteBuilder endpoints)
26+
/// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/>.</param>
27+
/// <returns>An <see cref="RazorComponentsEndpointConventionBuilder"/> that can be used to further configure the API.</returns>
28+
public static RazorComponentsEndpointConventionBuilder MapRazorComponents<[DynamicallyAccessedMembers(Component)] TRootComponent>(this IEndpointRouteBuilder endpoints)
2829
{
2930
ArgumentNullException.ThrowIfNull(endpoints);
3031

src/Components/Endpoints/src/Builder/RenderModeEndpointProvider.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
using Microsoft.AspNetCore.Routing;
88
using static Microsoft.AspNetCore.Internal.LinkerFlags;
99

10-
namespace Microsoft.AspNetCore.Components.Endpoints;
10+
namespace Microsoft.AspNetCore.Components.Endpoints.Infrastructure;
1111

1212
/// <summary>
1313
/// A provider that can register endpoints to support a specific <see cref="IComponentRenderMode"/>.

src/Components/Endpoints/src/Builder/RootComponentMetadata.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Components.Endpoints;
99
/// <summary>
1010
/// Metadata that represents the root component associated with an endpoint.
1111
/// </summary>
12-
public class RootComponentMetadata
12+
public sealed class RootComponentMetadata
1313
{
1414
/// <summary>
1515
/// Initializes a new instance of <see cref="RootComponentMetadata"/>.

src/Components/Endpoints/src/DependencyInjection/IRazorComponentsBuilder.cs

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using Microsoft.Extensions.DependencyInjection;
5-
6-
namespace Microsoft.AspNetCore.Components.Endpoints;
4+
namespace Microsoft.Extensions.DependencyInjection;
75

86
/// <summary>
97
/// A builder that can be used to configure Razor Components.

src/Components/Endpoints/src/DependencyInjection/RazorComponentOptions.cs

+2-11
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33

44
using Microsoft.AspNetCore.Components.Endpoints.FormMapping;
55

6-
namespace Microsoft.Extensions.DependencyInjection;
6+
namespace Microsoft.AspNetCore.Components.Endpoints;
77

88
/// <summary>
99
/// Provides options for configuring server-side rendering of Razor Components.
1010
/// </summary>
11-
public class RazorComponentOptions
11+
public sealed class RazorComponentsOptions
1212
{
1313
internal readonly FormDataMapperOptions _formMappingOptions = new();
1414

@@ -58,13 +58,4 @@ public int MaxFormMappingKeySize
5858
get => _formMappingOptions.MaxKeyBufferSize;
5959
set => _formMappingOptions.MaxKeyBufferSize = value;
6060
}
61-
62-
/// <summary>
63-
/// Gets or sets a value that determines whether the current culture should be used when mapping form data.
64-
/// </summary>
65-
public bool FormMappingUseCurrentCulture
66-
{
67-
get => _formMappingOptions.UseCurrentCulture;
68-
set => _formMappingOptions.UseCurrentCulture = value;
69-
}
7061
}

src/Components/Endpoints/src/DependencyInjection/RazorComponentsEndpointsOptions.cs renamed to src/Components/Endpoints/src/DependencyInjection/RazorComponentsEndpointOptions.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
namespace Microsoft.AspNetCore.Components.Endpoints;
55

6-
internal class RazorComponentsEndpointsOptions
6+
internal class RazorComponentsEndpointOptions
77
{
88
public bool DetailedErrors { get; set; }
99
}

src/Components/Endpoints/src/DependencyInjection/RazorComponentsEndpointsDetailedErrorsConfiguration.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
namespace Microsoft.Extensions.DependencyInjection;
1010

11-
internal class RazorComponentsEndpointsDetailedErrorsConfiguration : IConfigureOptions<RazorComponentsEndpointsOptions>
11+
internal class RazorComponentsEndpointsDetailedErrorsConfiguration : IConfigureOptions<RazorComponentsEndpointOptions>
1212
{
1313
public RazorComponentsEndpointsDetailedErrorsConfiguration(IConfiguration configuration)
1414
{
@@ -17,7 +17,7 @@ public RazorComponentsEndpointsDetailedErrorsConfiguration(IConfiguration config
1717

1818
public IConfiguration Configuration { get; }
1919

20-
public void Configure(RazorComponentsEndpointsOptions options)
20+
public void Configure(RazorComponentsEndpointOptions options)
2121
{
2222
var value = Configuration[WebHostDefaults.DetailedErrorsKey];
2323
options.DetailedErrors = string.Equals(value, "true", StringComparison.OrdinalIgnoreCase) ||

0 commit comments

Comments
 (0)