Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blazor Web template updates #49801

Merged
merged 36 commits into from
Aug 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
450bfba
Let the build process update some template strings
SteveSandersonMS Aug 2, 2023
233af92
Steps towards splitting the blazorweb template into two projects
SteveSandersonMS Aug 2, 2023
ec4f31e
Try renaming the server project to be the actual project name
SteveSandersonMS Aug 2, 2023
325595b
Update template.json
SteveSandersonMS Aug 2, 2023
d001124
Rename Components-CSharp to BlazorWeb-CSharp
SteveSandersonMS Aug 2, 2023
9c13f34
Add script for running locally
SteveSandersonMS Aug 2, 2023
f60fba0
More required renames
SteveSandersonMS Aug 2, 2023
f39fb76
Trying to switch between one project and two
SteveSandersonMS Aug 2, 2023
1e27e0f
Stop hiding wasm option
SteveSandersonMS Aug 2, 2023
d4efa4b
Add sln
SteveSandersonMS Aug 2, 2023
a0b0c3c
Add project reference
SteveSandersonMS Aug 2, 2023
99e8fda
Update default interactivity flags
SteveSandersonMS Aug 2, 2023
453e15f
Content changes to match plans
SteveSandersonMS Aug 2, 2023
029b98b
Fixes
SteveSandersonMS Aug 2, 2023
70c0bf6
Eliminate bootstrap-icons; inline the three we use
SteveSandersonMS Aug 2, 2023
3549249
Temporary workaround for inability to route to pages in referenced pr…
SteveSandersonMS Aug 2, 2023
f4c06bf
Towards PWAs
SteveSandersonMS Aug 2, 2023
d3c1e36
Move PWA content into WebAssembly project
SteveSandersonMS Aug 2, 2023
b9f2b1c
Remove PWA option. See #49798
SteveSandersonMS Aug 2, 2023
dae8116
Update templatestrings
SteveSandersonMS Aug 2, 2023
91733d0
Rename .WebAssembly project to .Client
SteveSandersonMS Aug 2, 2023
4269d5d
Stop adding pointless launchSettings.json
SteveSandersonMS Aug 2, 2023
d76f3cf
Add edge case RootNamespace/AssemblyName to .Client project
SteveSandersonMS Aug 2, 2023
efc27b2
Structural improvements
SteveSandersonMS Aug 2, 2023
b36c157
Split some lines
SteveSandersonMS Aug 3, 2023
9c48280
Make CSS links external. Rename Sidebar back to NavMenu.
SteveSandersonMS Aug 3, 2023
bf521b4
Simplify import
SteveSandersonMS Aug 3, 2023
01a402f
Make scoped CSS work
SteveSandersonMS Aug 3, 2023
fab438c
Starting on empty flag
SteveSandersonMS Aug 3, 2023
e5108c2
Empty updates
SteveSandersonMS Aug 3, 2023
306e8f3
Eliminate pointless css subdir
SteveSandersonMS Aug 3, 2023
25fccb4
Make Router NotFound optional
SteveSandersonMS Aug 3, 2023
9ad0865
Remove NotFound content in new template
SteveSandersonMS Aug 3, 2023
d0bf7ed
Drop the BOM
SteveSandersonMS Aug 3, 2023
6832248
Update template-baselines.json
SteveSandersonMS Aug 3, 2023
f5f7fc9
Move error UI css to be scoped
SteveSandersonMS Aug 3, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions src/Components/Components/src/Routing/Router.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Reflection.Metadata;
using System.Runtime.ExceptionServices;
using Microsoft.AspNetCore.Components.HotReload;
using Microsoft.AspNetCore.Components.Rendering;
using Microsoft.Extensions.Logging;

namespace Microsoft.AspNetCore.Components.Routing;
Expand Down Expand Up @@ -64,7 +65,6 @@ static readonly IReadOnlyDictionary<string, object> _emptyParametersDictionary
/// Gets or sets the content to display when no match is found for the requested route.
/// </summary>
[Parameter]
[EditorRequired]
public RenderFragment NotFound { get; set; }

/// <summary>
Expand Down Expand Up @@ -126,13 +126,6 @@ public async Task SetParametersAsync(ParameterView parameters)
throw new InvalidOperationException($"The {nameof(Router)} component requires a value for the parameter {nameof(Found)}.");
}

// NotFound content is mandatory, because even though we could display a default message like "Not found",
// it has to be specified explicitly so that it can also be wrapped in a specific layout
if (NotFound == null)
{
throw new InvalidOperationException($"The {nameof(Router)} component requires a value for the parameter {nameof(NotFound)}.");
}

if (!_onNavigateCalled)
{
_onNavigateCalled = true;
Expand Down Expand Up @@ -233,7 +226,7 @@ internal virtual void Refresh(bool isNavigationIntercepted)
// We did not find a Component that matches the route.
// Only show the NotFound content if the application developer programatically got us here i.e we did not
// intercept the navigation. In all other cases, force a browser navigation since this could be non-Blazor content.
_renderHandle.Render(NotFound);
_renderHandle.Render(NotFound ?? DefaultNotFoundContent);
}
else
{
Expand All @@ -243,6 +236,17 @@ internal virtual void Refresh(bool isNavigationIntercepted)
}
}

private static void DefaultNotFoundContent(RenderTreeBuilder builder)
{
// This output can't use any layout (none is specified), and it can't use any web-specific concepts
// such as <p role="alert">, and we can't localize the output. However none of that matters because
// in all cases we expect either:
// 1. The app to be hosted with MapRazorPages, and then it will never use any NotFound content
// 2. Or, the app to supply its own NotFound content
// ... so this is just a fallback for badly-set-up apps.
builder.AddContent(0, "Not found");
}

internal async ValueTask RunOnNavigateAsync(string path, bool isNavigationIntercepted)
{
// Cancel the CTS instead of disposing it, since disposing does not
Expand Down
47 changes: 44 additions & 3 deletions src/Components/Components/test/Routing/RouterTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ public async Task UsesCurrentRouteMatchingIfSpecified()
// Arrange
// Current routing prefers exactly-matched patterns over {*someWildcard}, no matter
// how many segments are in the exact match
_navigationManager.NotifyLocationChanged("https://www.example.com/subdir/a/b", false);
_navigationManager.NotifyLocationChanged("https://www.example.com/subdir/a/b/c", false);
var parameters = new Dictionary<string, object>
{
{ nameof(Router.AppAssembly), typeof(RouterTest).Assembly },
Expand Down Expand Up @@ -224,6 +224,47 @@ await _renderer.Dispatcher.InvokeAsync(() =>
Assert.Equal(1, refreshCalled);
}

[Fact]
public async Task UsesNotFoundContentIfSpecified()
{
// Arrange
_navigationManager.NotifyLocationChanged("https://www.example.com/subdir/nonexistent", false);
var parameters = new Dictionary<string, object>
{
{ nameof(Router.AppAssembly), typeof(RouterTest).Assembly },
{ nameof(Router.NotFound), (RenderFragment)(builder => builder.AddContent(0, "Custom content")) },
};

// Act
await _renderer.Dispatcher.InvokeAsync(() =>
_router.SetParametersAsync(ParameterView.FromDictionary(parameters)));

// Assert
var renderedFrame = _renderer.Batches.First().ReferenceFrames.First();
Assert.Equal(RenderTreeFrameType.Text, renderedFrame.FrameType);
Assert.Equal("Custom content", renderedFrame.TextContent);
}

[Fact]
public async Task UsesDefaultNotFoundContentIfNotSpecified()
{
// Arrange
_navigationManager.NotifyLocationChanged("https://www.example.com/subdir/nonexistent", false);
var parameters = new Dictionary<string, object>
{
{ nameof(Router.AppAssembly), typeof(RouterTest).Assembly }
};

// Act
await _renderer.Dispatcher.InvokeAsync(() =>
_router.SetParametersAsync(ParameterView.FromDictionary(parameters)));

// Assert
var renderedFrame = _renderer.Batches.First().ReferenceFrames.First();
Assert.Equal(RenderTreeFrameType.Text, renderedFrame.FrameType);
Assert.Equal("Not found", renderedFrame.TextContent);
}

internal class TestNavigationManager : NavigationManager
{
public TestNavigationManager() =>
Expand Down Expand Up @@ -260,9 +301,9 @@ public class FebComponent : ComponentBase { }
[Route("jan")]
public class JanComponent : ComponentBase { }

[Route("{*matchAnything}")]
[Route("a/{*matchAnything}")]
public class MatchAnythingComponent : ComponentBase { }

[Route("a/b")]
[Route("a/b/c")]
public class MultiSegmentRouteComponent : ComponentBase { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">

<PropertyGroup>
<TargetFramework>${DefaultNetCoreTargetFramework}</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NoDefaultLaunchSettingsFile>true</NoDefaultLaunchSettingsFile>
<StaticWebAssetProjectMode>Default</StaticWebAssetProjectMode>
<RootNamespace Condition="'$(name)' != '$(name{-VALUE-FORMS-}safe_namespace)'">BlazorWeb-CSharp.Client</RootNamespace>
<AssemblyName Condition="'$(name)' != '$(name{-VALUE-FORMS-}safe_namespace)'">`$(AssemblyName.Replace(' ', '_'))</AssemblyName>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="${MicrosoftAspNetCoreComponentsWebAssemblyVersion}" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>${DefaultNetCoreTargetFramework}</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<NoDefaultLaunchSettingsFile Condition="'$(ExcludeLaunchSettings)' == 'True'">True</NoDefaultLaunchSettingsFile>
<RootNamespace Condition="'$(name)' != '$(name{-VALUE-FORMS-}safe_namespace)'">BlazorWeb-CSharp</RootNamespace>
<AssemblyName Condition="'$(name)' != '$(name{-VALUE-FORMS-}safe_namespace)'">`$(AssemblyName.Replace(' ', '_'))</AssemblyName>
</PropertyGroup>
<!--#if UseWebAssembly -->

<ItemGroup>
<ProjectReference Include="..\BlazorWeb-CSharp.Client\BlazorWeb-CSharp.Client.csproj" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="${MicrosoftAspNetCoreComponentsWebAssemblyServerVersion}" />
</ItemGroup>
<!--#endif -->

</Project>

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@
<GeneratedContent Include="WebApi-FSharp.fsproj.in" OutputPath="content/WebApi-FSharp/Company.WebApplication1.fsproj" />
<GeneratedContent Include="Worker-CSharp.csproj.in" OutputPath="content/Worker-CSharp/Company.Application1.csproj" />
<GeneratedContent Include="Worker-FSharp.fsproj.in" OutputPath="content/Worker-FSharp/Company.Application1.fsproj" />
<GeneratedContent Include="Components-CSharp.csproj.in" OutputPath="content/Components-CSharp/Components-CSharp.csproj" />
<GeneratedContent Include="BlazorWeb-CSharp.csproj.in" OutputPath="content/BlazorWeb-CSharp/BlazorWeb-CSharp/BlazorWeb-CSharp.csproj" />
<GeneratedContent Include="BlazorWeb-CSharp.Client.csproj.in" OutputPath="content/BlazorWeb-CSharp/BlazorWeb-CSharp.Client/BlazorWeb-CSharp.Client.csproj" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other template that we have is components-webassembly could we have consistent naming between the two? (Either BlazorWebassembly or ComponentsWeb`)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'd like to change the other template's name to BlazorWebAssembly (to match everything else about its branding) and eliminate the "empty" variant in favour of a flag on BlazorWebAssembly. Just not trying to do that as part of this PR.

<GeneratedContent Include="ComponentsWebAssembly-CSharp.csproj.in" OutputPath="content/ComponentsWebAssembly-CSharp/ComponentsWebAssembly-CSharp.csproj" />
<GeneratedContent Include="EmptyComponentsWebAssembly-CSharp.csproj.in" OutputPath="content/EmptyComponentsWebAssembly-CSharp/EmptyComponentsWebAssembly-CSharp.csproj" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@
"longName": "no-restore",
"shortName": ""
},
"PWA": {
"longName": "pwa",
"isHidden": true
},
"UseServer": {
"longName": "use-server"
},
"UseWebAssembly": {
"longName": "use-wasm",
"longName": "use-wasm"
},
"Empty": {
"longName": "empty"
},
"IncludeSampleContent": {
Comment on lines 11 to +17
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not block on this, but we were talking in the past of making blazor web bring in server and webassembly by default.

The reason we did opt-in as opposed to opt-out was that we didn't have the underlying features in place. Do we want to keep that model (opt-in) or do we want to switch to opt-out.

/cc: @danroth27

Copy link
Member Author

@SteveSandersonMS SteveSandersonMS Aug 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dan and I did discuss this and came to the conclusion that server-on-by-default, wasm-off-by-default was the preferred balance for .NET 8. We're certainly free to change that in the future if we so choose.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@javiercn I want interactivity to work by default, but I'm concerned about the complexity that WebAssembly currently adds. I'm thinking about the getting started experience here for new users. Granted, the downside of having WebAssembly off by default is that if you later want to add it, it's not easy to do.

"isHidden": true
},
"Framework": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,17 @@
},
{
"id": "UseWebAssembly",
"isVisible": false,
"isVisible": true,
"persistenceScope": "templateGroup"
},
{
"id": "PWA",
"isVisible": false,
"persistenceScope": "templateGroup"
"id": "UseProgramMain",
"isVisible": true,
"persistenceScope": "shared",
"persistenceScopeName": "Microsoft"
},
{
"id": "UseProgramMain",
"id": "IncludeSampleContent",
"isVisible": true,
"persistenceScope": "shared",
"persistenceScopeName": "Microsoft"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
"symbols/UseWebAssembly/description": "Pokud je zadáno, nakonfiguruje projekt tak, aby vykreslovat komponenty interaktivně v prohlížeči pomocí WebAssembly.",
"symbols/UseServer/displayName": "_Použít interaktivní serverové komponenty",
"symbols/UseServer/description": "Pokud je zadáno, nakonfiguruje projekt tak, aby vykresloval komponenty interaktivně na serveru.",
"symbols/PWA/displayName": "_Progresivní webová aplikace",
"symbols/PWA/description": "Pokud je tato možnost zadaná, vytvoří progresivní webovou aplikaci (PWA), která podporuje instalaci a offline použití.",
"symbols/IncludeSampleContent/displayName": "_Include sample pages",
"symbols/IncludeSampleContent/description": "Configures whether to add sample pages and styling to demonstrate basic usage patterns.",
"symbols/Empty/description": "Configures whether to omit sample pages and styling that demonstrate basic usage patterns.",
"symbols/NoHttps/description": "Určuje, jestli se má protokol HTTPS vypnout. Tato možnost platí jenom v případě, že se pro --auth nepoužívají Individual, IndividualB2C, SingleOrg ani MultiOrg.",
"symbols/UseProgramMain/displayName": "Nepoužívat _příkazy nejvyšší úrovně",
"symbols/UseProgramMain/description": "Určuje, jestli se má místo příkazů nejvyšší úrovně generovat explicitní třída Program a metoda Main.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
"symbols/UseWebAssembly/description": "Bei Angabe dieser Option wird das Projekt so konfiguriert, dass Komponenten interaktiv mithilfe von WebAssembly im Browser gerendert werden.",
"symbols/UseServer/displayName": "_Interaktive Serverkomponenten verwenden",
"symbols/UseServer/description": "Bei Angabe dieser Option wird das Projekt so konfiguriert, dass Komponenten interaktiv auf dem Server gerendert werden.",
"symbols/PWA/displayName": "_Progressive Webanwendung",
"symbols/PWA/description": "Wenn angegeben, wird eine Progressive Web Application (PWA) erstellt, die die Installation und Offlineverwendung unterstützt.",
"symbols/IncludeSampleContent/displayName": "_Include sample pages",
"symbols/IncludeSampleContent/description": "Configures whether to add sample pages and styling to demonstrate basic usage patterns.",
"symbols/Empty/description": "Configures whether to omit sample pages and styling that demonstrate basic usage patterns.",
"symbols/NoHttps/description": "Ob HTTPS deaktiviert werden soll. Diese Option gilt nur, wenn Individual, IndividualB2C, SingleOrg oder MultiOrg nicht für --auth verwendet werden.",
"symbols/UseProgramMain/displayName": "Keine Anweisungen_der obersten Ebene verwenden",
"symbols/UseProgramMain/description": "Gibt an, ob anstelle von Anweisungen der obersten Ebene eine explizite Programmklasse und eine Main-Methode generiert werden soll.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
"symbols/iisHttpPort/description": "Port number to use for the IIS Express HTTP endpoint in launchSettings.json.",
"symbols/iisHttpsPort/description": "Port number to use for the IIS Express HTTPS endpoint in launchSettings.json. This option is only applicable when the parameter no-https is not used (no-https will be ignored if either IndividualAuth or OrganizationalAuth is used).",
"symbols/UseWebAssembly/displayName": "_Use interactive WebAssembly components",
"symbols/UseWebAssembly/description": "If specified, configures the project to render components interactively in the browser using WebAssembly.",
"symbols/UseWebAssembly/description": "Configures whether to support rendering components interactively in the browser using WebAssembly. The default value is false.",
"symbols/UseServer/displayName": "_Use interactive server components",
"symbols/UseServer/description": "If specified, configures the project to render components interactively on the server.",
"symbols/PWA/displayName": "_Progressive Web Application",
"symbols/PWA/description": "If specified, produces a Progressive Web Application (PWA) supporting installation and offline use.",
"symbols/UseServer/description": "Configures whether to support rendering components interactively on the server via a SignalR WebSocket connection. The default value is true.",
"symbols/IncludeSampleContent/displayName": "_Include sample pages",
"symbols/IncludeSampleContent/description": "Configures whether to add sample pages and styling to demonstrate basic usage patterns.",
"symbols/Empty/description": "Configures whether to omit sample pages and styling that demonstrate basic usage patterns.",
"symbols/NoHttps/description": "Whether to turn off HTTPS. This option only applies if Individual, IndividualB2C, SingleOrg, or MultiOrg aren't used for --auth.",
"symbols/UseProgramMain/displayName": "Do not use _top-level statements",
"symbols/UseProgramMain/description": "Whether to generate an explicit Program class and Main method instead of top-level statements.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
"symbols/UseWebAssembly/description": "Si se especifica, esta opción configura el proyecto para representar los componentes de forma interactiva en el explorador mediante WebAssembly.",
"symbols/UseServer/displayName": "_Use componentes de servidor interactivos",
"symbols/UseServer/description": "Si se especifica, esta opción configura el proyecto para representar los componentes de forma interactiva en el servidor.",
"symbols/PWA/displayName": "_Aplicación web progresiva",
"symbols/PWA/description": "Si se especifica, produce una aplicación web progresiva (PWA) compatible con la instalación y el uso sin conexión.",
"symbols/IncludeSampleContent/displayName": "_Include sample pages",
"symbols/IncludeSampleContent/description": "Configures whether to add sample pages and styling to demonstrate basic usage patterns.",
"symbols/Empty/description": "Configures whether to omit sample pages and styling that demonstrate basic usage patterns.",
"symbols/NoHttps/description": "Si se va a desactivar HTTPS. Esta opción solo se aplica si Individual, IndividualB2C, SingleOrg o MultiOrg no se usan para --auth.",
"symbols/UseProgramMain/displayName": "No usar instrucciones de _nivel superior",
"symbols/UseProgramMain/description": "Indica si se debe generar una clase Program explícita y un método Main en lugar de instrucciones de nivel superior.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
"symbols/UseWebAssembly/description": "S’il est spécifié, configure le projet pour afficher les composants de manière interactive dans le navigateur à l’aide de WebAssembly.",
"symbols/UseServer/displayName": "_Utiliser les composants serveur interactifs",
"symbols/UseServer/description": "Si ce paramètre est spécifié, configure le projet pour afficher les composants de manière interactive sur le serveur.",
"symbols/PWA/displayName": "_Application web progressive",
"symbols/PWA/description": "Si ce paramètre est spécifié, produit une application web progressive (PWA) qui prend en charge l’installation et l’utilisation hors connexion.",
"symbols/IncludeSampleContent/displayName": "_Include sample pages",
"symbols/IncludeSampleContent/description": "Configures whether to add sample pages and styling to demonstrate basic usage patterns.",
"symbols/Empty/description": "Configures whether to omit sample pages and styling that demonstrate basic usage patterns.",
"symbols/NoHttps/description": "Indique s’il faut désactiver HTTPS. Cette option s’applique uniquement si Individual, IndividualB2C, SingleOrg ou MultiOrg ne sont pas utilisés pour --auth.",
"symbols/UseProgramMain/displayName": "N’utilisez pas _d’instructions de niveau supérieur.",
"symbols/UseProgramMain/description": "Indique s’il faut générer une classe Programme explicite et une méthode Main au lieu d’instructions de niveau supérieur.",
Expand Down
Loading