105

I need to know the URL of the current page in order to check if I have to apply a certain style to an element. The code below is an example.

    @using Microsoft.AspNetCore.Blazor.Services
    @inject IUriHelper UriHelper
    @implements IDisposable

    <h1>@url</h1>
    <nav>
        <div class="nav-wrapper">
            <a href="#" class="brand-logo">Blazor</a>
            <ul id="nav-mobile" class="right hide-on-med-and-down">
                <li>
                    <NavLink href="/" Match=NavLinkMatch.All>
                        Home
                    </NavLink>
                </li>
                <li>
                    <NavLink href="/counter">
                        Counter
                    </NavLink>
                </li>
                <li>
                    <NavLink href="/fetchdata">
                        Fetch data
                    </NavLink>
                </li>
            </ul>
        </div>
    </nav>

    @functions {

        private string url = string.Empty;

        protected override void OnInit()
        {
            url = UriHelper.GetAbsoluteUri();
            UriHelper.OnLocationChanged += OnLocationChanged;
        }

        private void OnLocationChanged(object sender, LocationChangedEventArgs e)
        {
            url = newUriAbsolute;
        }

        public void Dispose()
        {
            UriHelper.OnLocationChanged -= OnLocationChanged;
        }
    }

I used the same approach used in the NavLink component in the Blazor repository, but it did not work. Any ideas?.

dani herrera
  • 48,760
  • 8
  • 117
  • 177
Carlos L.
  • 1,159
  • 2
  • 8
  • 5

6 Answers6

223

Use the Uri property from the NavigationManager class.

How it works

Get it from injection before using it on .razor pages:

@inject NavigationManager MyNavigationManager

Or like this in a .cs file if you prefer the "code-behind" experience:

using Microsoft.AspNetCore.Components;
// ...
[Inject]
public NavigationManager MyNavigationManager {get; set;} = default!;

Sample

@page "/navigate"
@inject NavigationManager MyNavigationManager

<h1>Current URL</h1>

<p>@(MyNavigationManager.Uri)</p>

More about navigation (NavigateTo, BaseUri, ToAbsoluteUri, ToBaseRelativePath, ... ) at: URI and navigation state helpers

NavigationManager cheatsheet

MyNavigationManager.Uri
#> https://localhost:5001/counter/3?q=hi

MyNavigationManager.BaseUri
#> https://localhost:5001/

MyNavigationManager.NavigateTo("http://new location")
#> Navigates to new location

MyNavigationManager.LocationChanged
#> An event that fires when the navigation location has changed.

MyNavigationManager.ToAbsoluteUri("pepe")
#> https://localhost:5001/pepe

MyNavigationManager.ToBaseRelativePath(MyNavigationManager.Uri)
#> counter/3?q=hi

Helper: AddQueryParm( "q2", "bye" ) // (*1)
#> https://localhost:5001/counter/3?q=hi&q2=bye

Helper: GetQueryParm( "q" )
#> hi

(*1) Net6 introduces GetUriWithQueryParameter. More info: Manipulate the query string from Blazor

Helpers code:

@code {

    [Parameter]
    public string Id { get; set; }

    // Blazor: add parm to URL
    string AddQueryParm(string parmName, string parmValue)
    {
        var uriBuilder = new UriBuilder(MyNavigationManager.Uri);
        var q = System.Web.HttpUtility.ParseQueryString(uriBuilder.Query);
        q[parmName] = parmValue;
        uriBuilder.Query = q.ToString();
        var newUrl = uriBuilder.ToString();
        return newUrl;
    }

    // Blazor: get query parm from the URL
    string GetQueryParm(string parmName)
    {
        var uriBuilder = new UriBuilder(MyNavigationManager.Uri);
        var q = System.Web.HttpUtility.ParseQueryString(uriBuilder.Query);
        return q[parmName] ?? "";
    }

}
dani herrera
  • 48,760
  • 8
  • 117
  • 177
  • 2
    starting with v0.8.0 when using server side mode you should use: `@inject Microsoft.AspNetCore.Components.Services.IUriHelper UriHelper` and when using client-side mode: `@inject Microsoft.AspNetCore.Blazor.Services.WebAssemblyUriHelper UriHelper` – Henry Rodriguez Feb 09 '19 at 20:17
  • 6
    @ Henry Rodriguez, no, you're wrong. The correct way is to inject IUriHelper, not the implementation.. – enet Mar 25 '19 at 21:12
  • It's not working if usert try to force to another page over the Url address – Bcktr Jun 29 '20 at 09:06
  • 2
    The cheatsheet is very helpful +1 – puerile May 08 '22 at 14:17
9

First of all, inject NavigationManager into the component in which you need to get the current URL as below:

@inject NavigationManager NavManager

Now use the below line to get the current URL:

string Url = NavManager.Uri.ToString();
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
Jalpesh Nakum
  • 131
  • 1
  • 4
4

There is no use in connecting to the OnLocationChanged event in a page or component, as they get loaded and disposed on demand.

You should register to this event in app.cshtml as that won't be disposed.

Flores
  • 8,226
  • 5
  • 49
  • 81
3

You should listen to a LocationChange of the IUriHelper, which triggers the function to do what you want for example:

@using Microsoft.AspNetCore.Blazor.Components
@using Microsoft.Extensions.Logging
@inject Microsoft.AspNetCore.Blazor.Services.IUriHelper UriHelper
@inject ILogger<NavItem> logger

<li class="m-menu__item @(Active ? "m-menu__item--active" : "")">
    <a href=@Url class="m-menu__link ">
        <span class="m-menu__item-here"></span>
        <i class="m-menu__link-icon @Icon"></i>
        <span class="m-menu__link-text">@Text</span>
    </a>
</li>

@functions {
    protected override void OnInit()
    {
        UriHelper.OnLocationChanged += OnLocationChanges;
    }
    [Parameter]
    private string Url { get; set; }
    [Parameter]
    private string Icon { get; set; }
    [Parameter]
    private string Text { get; set; }
    private bool Active = false;
    private void OnLocationChanges(object sender, string newLocation)
    {
        bool active = newLocation.Contains(Url);
        if(active != Active) //Only re-render the components that need it
        {
            Active = active;
            StateHasChanged();
            logger.LogInformation("Location Change To:" + newLocation);
        }
    }
}
Verbe
  • 634
  • 7
  • 13
  • This UriHelper.OnLocationChanged event has new parameters that were causing an error with this example with .netCore 3 preview6. Should be: private void OnLocationChanges(object sender, LocationChangedEventArgs e) – Enkode Jul 12 '19 at 18:22
  • 3
    this answer was for an out-dated version of blazor, use NavigationManager now. – sowen Jan 13 '20 at 05:49
3

In my case I only needed the Uri of the page and not the base Uri aswell.

I keep all my code in a razor.cs file so I inject NavigationManager from code-behind like this:

[Inject] public NavigationManager Navigation { get; set; } 

Navigation.Uri yeilds: https://localhost:5001/nail-square-singel-shear-timber-timber

So to get the page Uri just do like this:

Navigation.Uri.Replace(Navigation.BaseUri,"")

The above yields: nail-square-singel-shear-timber-timber

1

Create somewhere an extension method like this:

namespace YourSolution.YourProject
{
    public static class NavigationManagerExtention
    {
        public static string Page(this NavigationManager navigation)
        {
            return navigation.Uri.Substring(navigation.BaseUri.Length - 1);
        }
    }
}

and to get the page part of URL just call _nav.Page()

Examples:

  • For example.com/home it returns /home
  • For example.com/ it returns /

If you don't need a slash char (/) replace

return navigation.Uri.Substring(navigation.BaseUri.Length - 1);

with

return navigation.Uri.Substring(navigation.BaseUri.Length);
Alex Logvin
  • 766
  • 10
  • 12