Get Current Url in a Blazor Component

How to access current route using Blazor component

How to access current route using Blazor component

This title is misleading and you should change it. You can't access the
the current route in order to do that task, as the current route does
not exist yet

I have searched up this question multiple times and each solution has
not worked for me, using HttpContext has not worked either.

Again, the solution is not by using the current route as no route has
already been created. Your components are not yet created, so no route
is available

HttpContext is not available in Blazor, most of the time, if at all...

Solution:

Add this code to the MainLayout component

  1. Define a property of type Type. This property will be populated with
    the Type ( component) that is going to be created

  2. You can retrieve the type of the component from the OnParametersSet
    method of the MainLayout component

  3. When you start your project, the Type is Index
    (Note that it is returned in the form: <projectname>.Pages.Index)

  4. If you type in your browser the url of your app + "/counter",
    as for instance: https://localhost:44373/counter, you'll get
    <projectname>.Pages.Counter



 @code{

public Type PageType { get; set; }

protected override void OnParametersSet()
{

PageType = (this.Body.Target as RouteView)?.RouteData.PageType;

Console.WriteLine("This is your type (current type)" +
PageType);
}
}

At the top of the MainLayout.razor file the <NavMenu /> is instantiated. Add to it an attribute parameter named PageType, as follows:

<NavMenu PageType="@PageType" />

The PageType on the left side should be defined in the NavMenu component. As you can see it is bound to the PageType property defined in MainLayout.

Now you should define the parameter property named PageType in NavMenu like this:

NavMenu.razor

@code {
[Parameter]
public Type PageType { get; set; }
}

Now, you have the current Type (component) available in your NavMenu
component, and you can use it as you please.

It is essential that you understand how components are rendered... which comes first, next etc. And much much more...

But hey, you're going to have tough time managing your task... The following code snippet demonstrates, very roughly that what you intend to do is workable( My code is fine and does the job, and the issues you're going to have are not related to it).

NavMenu.razor

<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">

@switch (PageType.ToString())
{
case "BlazorApp4.Pages.Index":
@*<header>
<div>
<nav>
<ul class="main-menu">
<li id="CurPage">Home</li>
<li class="menu-item">Shop</li>
<li class="menu-item">FAQ</li>
<li class="menu-item">About</li>
</ul>
</nav>
</div>
</header>*@

<ul class="nav flex-column">
<li class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="oi oi-home" aria-hidden="true"></span> Home
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="counter">
<span class="oi oi-plus" aria-hidden="true"></span> Counter
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="fetchdata">
<span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
</NavLink>
</li>
</ul>
break;
case "Shop":
<header>
<div>
<nav>
<ul class="main-menu">
<li class="menu-item">Home</li>
<li id="CurPage">Shop</li>
<li class="menu-item">FAQ</li>
<li class="menu-item">About</li>
</ul>
</nav>
</div>
</header>
break;
case "FAQ":
<header>
<div>
<nav>
<ul class="main-menu">
<li class="menu-item">Home</li>
<li Class="menu-item">Shop</li>
<li id="CurPage">FAQ</li>
<li class="menu-item">About</li>
</ul>
</nav>
</div>
</header>
break;
case "About":
<header>
<div>
<nav>
<ul class="main-menu">
<li class="menu-item">Home</li>
<li class="menu-item">Shop</li>
<li class="menu-item">FAQ</li>
<li id="CurPage">About</li>
</ul>
</nav>
</div>
</header>
break;
}
</div>

The code above is going to display the default links to the default template pages, when you start your page. (Index page). Comment out the code in the case "BlazorApp4.Pages.Index:, and uncomment your code (...) located under case "BlazorApp4.Pages.Index":

Lo and behold, total darkness... here comes your pains...work hard...good luck.

How to Get the Base Url of a Server-Side Blazor App

Getting it inside a page is easy:

@inject NavigationManager Navigator

<p>@Navigator.BaseUri</p>

But you can't use a NavigationManager in the Startup class.

Blazor retrieve relative url

It's not Blazor specific, we have the Uri class:

var uri = new Uri(@"https://www.mywebsite.com/someoverview");
var relativePath = uri.LocalPath; // or .PathAndQuery

or for the current Blazor page:

@inject NavigationManager Navigator

<a href="@Navigator.ToBaseRelativePath(Navigator.Uri)">here</a>

but do note that ToBaseRelativePath() does not include a leading /, it is different from LocalPath. You can mix & match.

How to get component type from location/url/route

You can add an OnParametersSet method in your MainLayout component...

Also add: @using System.Reflection;

protected override void OnParametersSet()
{
// Get the Component Type from the route data
var component = (this.Body.Target as RouteView)?.RouteData.PageType;

// Get a list of all the interfaces implemented by the component.
// It should be: IComponent, IHandleEvent, IHandleAfterRender,
// Unless your routable component has derived from ComponentBase,
// and added interface implementations of its own
var allInterfaces = component.GetInterfaces();


}

Blazor - How to get layout @Body path?

Blazor provides the NavigationManager for this purpose (see Blazor routing):

@inject NavigationManager NavigationManager;

protected override void OnInitialized()
{
breadCrumbDatas = breadCrumbService.GetProperList();

// Get everything after the domain + '/' (e.g. after "https://example.com/")
path = NavigationManager.Uri.Substring(Navigator.BaseUri.Length);

// You can also listen for a path change by subscribing to
// NavigationManager.LocationChanged.
}

A couple notes/suggestions:

  • Since NavigationManager can be injected, you don't need to pass it down to your BreadCrumbs component as a parameter (unless you are using the component for something other than URL paths). You can directly inject it into your BreadCrumbs component:
@inject NavigationManager NavigationManager;

<nav aria-label="breadcrumb">
<ol class="breadcrumb">
  • @Body isn't a component: it is a RenderFragment.
  • @Body doesn't have a path, per se; pages (designated with @page) do. Routing is managed by App.razor and configured in Startup.cs.

Logging URL in Blazor Server using Nlog

Right now, it doesn't seem to be possible to use NLog layout renderers such as ${aspnet-request-url} to log the correct request url for Blazor Server applications, but you can still make it work by appending the request URL to the logger yourself by using the ${event-properties} layout renderer (see code below).

The reason is that ${aspnet-request-url} layout renderer searches HttpContext.Request to get the request URL (NLog AspNetRequestUrlRenderer.cs), which works fine for other asp.net core projects, but Blazor handles things differently.

In-case of Blazor Server applications, clients only send an HTTP request to the application just once (to https://localhost/_blazor), in which they download all the necessary files (html / css / js / images) and Blazor establishes a SignalR connection with the client. Once a SignalR connection is established, it uses transport methods other than HTTP (usually WebSockets) for communicating between the client-server and no HTTP request is made after that. All subsequent requests are made through SignalR connection and therefore, you always get https://localhost/_blazor in ${aspnet-request-url} layout renderer.

As per the documentation, the defined way to get current requests URI is to inject NavigationManager in your Blazor components. You can get the Uri property from NavigationManager which gives you an absolute URI in string format. NLog loggers can be enriched with context information and custom properties (using WithProperty or WithProperties method) which can then be logged using Event Properties layout renderer. So what you can do is attach the NavigationManager.Uri to your logger and then access that property by defining it in your layouts in NLog.config.

Solution #01 Example:

/* Counter.razor */
@page "/counter"

@inject NavigationManager navigationManager

/* Define Logger */
NLog.Logger _logger = NLog.LogManager.GetCurrentClassLogger();

/* Attaching a property to a logger returns a new enriched logger */
var loggerWithProps = _logger.WithProperty("navigation-manager-uri", navigationManager.Uri);

/* Use this logger which has request url attached in key 'navigation-manager-uri' */
loggerWithProps.Info("Sample message which contains NavManager.Uri property");

Now in your NLog.config file, you can access the request uri using the layout renderer ${event-properties:item=navigation-manager-uri}. Your config file will look like this:

<!-- NLog.config -->
<targets>
<target xsi:type="Console" layout="${event-properties:item=navigation-manager-uri} ${message}">

<!-- Or skip logging this property if it is empty (uses ${when} condition) -->
<!-- <target xsi:type="Console" layout="${when:when='${event-properties:item=navigation-manager-uri}'!='':Inner=${event-properties:item=navigation-manager-uri} }${message}"> -->
</target>
</targets>

which gives the output logs:

https://localhost:7123/counter Sample message which contains NavManager.Uri property


[Recommended] Solution #02 Example (thanks @Rolf Kristensen)

Instead of enriching a logger by attaching a property to it (which creates 2 loggers, one with your property and one without it) and using ${event-properties} layout renderer, you can simple add NavigationManager.Uri into HttpContext.Items in OnInitialized lifecycle hook. Since NLog has HttpContext Item Layout Renderer which can access HttpContext.Items, you can access it in NLog.config by using ${aspnet-item:variable=YOUR_VARIABLE_NAME}

/* Counter.razor */
@page "/counter"

/* @* Inject NavigationManager to get current URI *@ */
@inject NavigationManager navigationManager

/* @* Inject IHttpContextAccessor to get access to current HttpContext *@ */
@inject IHttpContextAccessor httpContextAccessor

@code {
/* Define a simple logger */
NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

protected override void OnInitialized()
{
/* Add NavigationManager.Uri into HttpContext Items */
/* This will then be accessible in NLog.config like ${aspnet-item:variable=navigation-manager-uri} */
httpContextAccessor?.HttpContext?.Items.Add("navigation-manager-uri", navigationManager.Uri);

/* Or make it fail safe so that it doesn't give 'key' already present error when switching to multiple pages */
// if (httpContextAccessor is not null && httpContextAccessor.HttpContext is not null && httpContextAccessor.HttpContext.Items.ContainsKey("navigation-manager-uri"))
// httpContextAccessor?.HttpContext?.Items.Remove("navigation-manager-uri");
// httpContextAccessor?.HttpContext?.Items.Add("navigation-manager-uri", navigationManager.Uri);

/* Now logging anything will have correct URL displayed in logs */
/* Use this logger everywhere in this component */
logger.Info("This will have correct URL attached from NavigationManager.Uri");
}
}

Now in your NLog.config file, you can access the request URI which you pushed to HttpContext.Items using the layout renderer ${aspnet-item:variable=navigation-manager-uri}. Your config file will look like this:

<!-- NLog.config -->
<targets>
<target xsi:type="Console" layout="${aspnet-item:variable=navigation-manager-uri} ${message}">

<!-- Or skip logging this property if it is empty (uses ${when} condition) -->
<!-- <target xsi:type="Console" layout="${when:when='${aspnet-item:variable=navigation-manager-uri}'!='':Inner=${aspnet-item:variable=navigation-manager-uri} }${message}"> -->
</target>
</targets>

which gives the output logs:

https://localhost:7123/counter This will have correct URL attached from NavigationManager.Uri

This solution is easier because all you need to do is add 3 lines of code to make it work and NLog handles the rest.

  1. Inject NavigationManager
  2. Inject IHttpContextAccessor
  3. Add NavigationManager.Uri into HttpContext.Items

Right now these are the only ways to log the request URLs for Blazor applications with NLog. See NLog Issue - Provide support for logging Blazor request information for more information.



Related Topics



Leave a reply



Submit