Skip to content

Commit fe7074f

Browse files
committed
Fix templates and layout.
1 parent 0f52575 commit fe7074f

File tree

13 files changed

+91
-19
lines changed

13 files changed

+91
-19
lines changed

src/Components/Components/src/LayoutAttribute.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,6 @@ public LayoutAttribute([DynamicallyAccessedMembers(Component)] Type layoutType)
3636
/// The type of the layout. The type must implement <see cref="IComponent"/>
3737
/// and must accept a parameter with the name 'Body'.
3838
/// </summary>
39+
[DynamicallyAccessedMembers(Component)]
3940
public Type LayoutType { get; private set; }
4041
}

src/Components/Components/src/Routing/Router.cs

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ static readonly IReadOnlyDictionary<string, object> _emptyParametersDictionary
4242

4343
private bool _onNavigateCalled;
4444

45+
[DynamicallyAccessedMembers(LinkerFlags.Component)]
46+
private Type? _notFoundLayoutType;
47+
4548
[Inject] private NavigationManager NavigationManager { get; set; }
4649

4750
[Inject] private INavigationInterception NavigationInterception { get; set; }
@@ -156,6 +159,9 @@ public async Task SetParametersAsync(ParameterView parameters)
156159
throw new InvalidOperationException($"The type {NotFoundPage.FullName} " +
157160
$"does not have a {typeof(RouteAttribute).FullName} applied to it.");
158161
}
162+
163+
var layoutAttr = NotFoundPage.GetTypeInfo().GetCustomAttribute<LayoutAttribute>();
164+
_notFoundLayoutType = layoutAttr?.LayoutType;
159165
}
160166

161167
if (!_onNavigateCalled)
@@ -223,7 +229,7 @@ internal virtual void Refresh(bool isNavigationIntercepted)
223229
var relativePath = NavigationManager.ToBaseRelativePath(_locationAbsolute.AsSpan());
224230
var locationPathSpan = TrimQueryOrHash(relativePath);
225231
var locationPath = $"/{locationPathSpan}";
226-
Activity? activity = null;
232+
Activity? activity;
227233

228234
// In order to avoid routing twice we check for RouteData
229235
if (RoutingStateProvider?.RouteData is { } endpointRouteData)
@@ -286,7 +292,7 @@ internal virtual void Refresh(bool isNavigationIntercepted)
286292
// We did not find a Component that matches the route.
287293
// Only show the NotFound content if the application developer programatically got us here i.e we did not
288294
// intercept the navigation. In all other cases, force a browser navigation since this could be non-Blazor content.
289-
_renderHandle.Render(NotFound ?? DefaultNotFoundContent);
295+
RenderNotFound();
290296
}
291297
else
292298
{
@@ -382,23 +388,43 @@ private void OnNotFound(object sender, EventArgs args)
382388
if (_renderHandle.IsInitialized)
383389
{
384390
Log.DisplayingNotFound(_logger);
385-
_renderHandle.Render(builder =>
391+
RenderNotFound();
392+
}
393+
}
394+
395+
private void RenderNotFound()
396+
{
397+
_renderHandle.Render(builder =>
398+
{
399+
if (NotFoundPage != null)
386400
{
387-
if (NotFoundPage != null)
401+
if (_notFoundLayoutType is Type layoutType)
388402
{
389-
builder.OpenComponent(0, NotFoundPage);
403+
// Directly instantiate the layout type, supplying the NotFoundPage as the Body
404+
builder.OpenComponent(0, layoutType);
405+
builder.AddAttribute(1, LayoutComponentBase.BodyPropertyName,
406+
(RenderFragment)(childBuilder =>
407+
{
408+
childBuilder.OpenComponent(2, NotFoundPage);
409+
childBuilder.CloseComponent();
410+
}));
390411
builder.CloseComponent();
391412
}
392-
else if (NotFound != null)
393-
{
394-
NotFound(builder);
395-
}
396413
else
397414
{
398-
DefaultNotFoundContent(builder);
415+
builder.OpenComponent(0, NotFoundPage);
416+
builder.CloseComponent();
399417
}
400-
});
401-
}
418+
}
419+
else if (NotFound != null)
420+
{
421+
NotFound(builder);
422+
}
423+
else
424+
{
425+
DefaultNotFoundContent(builder);
426+
}
427+
});
402428
}
403429

404430
async Task IHandleAfterRender.OnAfterRenderAsync()

src/Components/test/E2ETest/ServerRenderingTests/NoInteractivityTest.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ public void CanRenderNotFoundPageNoStreaming(bool useCustomNotFoundPage)
136136
{
137137
var infoText = Browser.FindElement(By.Id("test-info")).Text;
138138
Assert.Contains("Welcome On Custom Not Found Page", infoText);
139+
// custom page should have a custom layout
140+
var aboutLink = Browser.FindElement(By.Id("about-link")).Text;
141+
Assert.Contains("About", aboutLink);
139142
}
140143
else
141144
{

src/Components/test/E2ETest/Tests/GlobalInteractivityTest.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ public void CanRenderNotFoundInteractive(string renderingMode, bool useCustomNot
3939
{
4040
var infoText = Browser.FindElement(By.Id("test-info")).Text;
4141
Assert.Contains("Welcome On Custom Not Found Page", infoText);
42+
// custom page should have a custom layout
43+
var aboutLink = Browser.FindElement(By.Id("about-link")).Text;
44+
Assert.Contains("About", aboutLink);
4245
}
4346
else
4447
{

src/Components/test/testassets/Components.WasmMinimal/Pages/CustomNotFoundPage.razor

Lines changed: 0 additions & 4 deletions
This file was deleted.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@page "/render-custom-not-found-page"
2+
@layout NotFoundLayout
3+
4+
<h3 id="test-info">Welcome On Custom Not Found Page</h3>
5+
<p>Sorry, the page you are looking for does not exist.</p>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
@inherits LayoutComponentBase
2+
3+
<div class="page">
4+
<header class="top-bar">
5+
<a href="https://learn.microsoft.com/aspnet/core/" target="_blank">About</a>
6+
</header>
7+
<main>
8+
<article class="content px-4">
9+
@Body
10+
</article>
11+
</main>
12+
</div>
13+
14+
<style>
15+
.top-bar {
16+
background-color: #0078d4;
17+
color: white;
18+
padding: 10px;
19+
text-align: center;
20+
width: 100%;
21+
box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.2);
22+
}
23+
</style>

src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp.Client/_Imports.razor

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,6 @@
1010
@using Microsoft.AspNetCore.Components.Web.Virtualization
1111
@using Microsoft.JSInterop
1212
@using BlazorWeb_CSharp.Client
13+
@*#if (!UseServer && UseWebAssembly && InteractiveAtRoot) -->
14+
@using BlazorWeb_CSharp.Client.Layout
15+
##endif*@
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
@page "/not-found"
2+
@layout MainLayout
23

34
<h3>Not Found</h3>
45
<p>Sorry, the content you are looking for does not exist.</p>

src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/_Imports.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@
1717
@using BlazorWeb_CSharp.Client.Layout
1818
##endif*@
1919
@using BlazorWeb_CSharp.Components
20-
@*#if (UseServer && (!UseWebAssembly || !InteractiveAtRoot)) -->
20+
@*#if (UseServer || !InteractiveAtRoot) -->
2121
@using BlazorWeb_CSharp.Components.Layout
2222
##endif*@

0 commit comments

Comments
 (0)