I use Blazor wasm. I want to check all the requests to the Blazor App and if a request Url starts with @ like localhost:5000/@michel
, redirect it to a specific component, like a middleware in asp core that can catch all requests. How can I do this?
CodePudding user response:
I'm making the assumption that under normal circumstances no route exists for @michel
and you get a Sorry, there's nothing at this address. message.
In which case you should be able to modify the NotFound
content of Router
.
Here's the modified version of App
. UserRouteFound
is a new component that does the magic: it detects username requests and loads UserPage
.
<Router AppAssembly="@typeof(App).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
<NotFound>
<UserRouteFound Layout="@typeof(MainLayout)" UserForm="@typeof(UserPage)">
<PageTitle>Not found</PageTitle>
<LayoutView Layout="@typeof(MainLayout)">
<p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>
</UserRouteFound>
</NotFound>
</Router>
UserNotFound.cs
It implements IComponent
.
The key bits are:
TryGetUserName
checks if there is a@
and gets the username. This is simplistic, you probably want to be more specific and use a RegEx.We try and get a username in
SetParametersAsync
and populate_username
.Render
loads the component defined inUserForm
instead of theNot Found
content if we have a username.
The IComponent
implementatiion stuff is fairly standard MS DotNetCore fare.
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;
namespace xxxxx;
public class UserRouteFound : IComponent
{
private RenderHandle _renderHandle;
private readonly RenderFragment _renderDelegate;
private string? _username;
[Inject] private NavigationManager NavigationManager { get; set; } = default!;
[Parameter, EditorRequired] public Type Layout { get; set; } = default!;
[Parameter, EditorRequired] public Type UserForm { get; set; } = default!;
[Parameter] public RenderFragment? ChildContent { get; set; }
public UserRouteFound()
=> _renderDelegate = Render;
public void Attach(RenderHandle renderHandle)
=> _renderHandle = renderHandle;
public Task SetParametersAsync(ParameterView parameters)
{
parameters.SetParameterProperties(this);
if (UserForm == null)
throw new InvalidOperationException($"The {nameof(RouteView)} component requires an IComponent UserForm class.");
_username = null;
if (TryGetUserName(out string? username))
_username = username;
_renderHandle.Render(_renderDelegate);
return Task.CompletedTask;
}
protected bool TryGetUserName(out string? value)
{
string? username = null;
var url = NavigationManager.Uri;
if (url.Contains("@"))
username = url.Substring(url.IndexOf("@"));
value = username;
return value is not null;
}
protected virtual void Render(RenderTreeBuilder builder)
=> _ = _username is not null
? RenderUserFound(builder)
: RenderNotFound(builder);
private bool RenderUserFound(RenderTreeBuilder builder)
{
builder.OpenComponent<LayoutView>(0);
builder.AddAttribute(1, nameof(LayoutView.Layout), Layout);
builder.AddAttribute(2, nameof(LayoutView.ChildContent), this.RenderUserForm);
builder.CloseComponent();
return true;
}
private bool RenderNotFound(RenderTreeBuilder builder)
{
builder.AddContent(0, this.ChildContent);
return true;
}
private RenderFragment RenderUserForm => (RenderTreeBuilder builder) =>
{
builder.OpenComponent(0, this.UserForm);
builder.AddAttribute(1, "UserName", _username);
builder.CloseComponent();
};
}
UserPage
Here's a very simplistic "UserForm".
<h3>UserPage</h3>
<div >
@this.UserName
</div>
@code {
[Parameter] public string UserName { get; set; } = string.Empty;
}