Search code examples
c#asp.net-mvcasp.net-coreblazorblazor-webassembly

Blazor NavigationManager go to Location without change Url


I have a dynamic rewrite mechanism.

In a table that I called Rewrite I store all keys and respectively the page and parameters I have to call.

For example:

Key Page Red Green Blue
red-products Products 255 0 0
green-products Products 0 255 0

In my Products.razor page the page directive is

@page/{red}/{green}/{blue}

and I have

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

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

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

In My Index.razor there is the start of this mechanism.

so it has this page directive

@page "/"
@page "/{key}"

In Index.razor.cs I have

public partial class Index : BaseComponent
{
    [Parameter]
    public string key { get; set; }
    [Inject] protected HttpClient Http { get; set; }
    [Inject] protected NavigationManager NavigationManager { get; set; }


    protected override async Task OnParametersSetAsync()
    {
        if (key != null)
        {
            Rewrite r = await Http.GetFromJsonAsync<Rewrite>($"api/Rewrite/GetRewriteByKey/{0}/{key}");
            
            NavigationManager.NavigateTo($"{r.Page}/{r.Red}/{r.Green}/{r.Blue}");
        }
        base.OnParametersSet();
    }
}

What I want to do is call Product page without changing url in browser, so keep pred-products in browser url but call Products page with parameters 255,0,0.

Is it Possible? or is there a smarter way to handle these rewrites?

In Asp.net web forms I'm using the same reasoning in the file global.asax and I use the command

Context.RewritePath($"{r.Page}/{r.Red}/{r.Green}/{r.Blue}");

Solution

  • If I've understood your question correctly, you can use DynamicComponent to manage your Page.

    The following code should demostrates hoe to use it.

    A Data Provider to provide the data - your API call.

    namespace SO77439144.Components.Pages;
    
    public record MyData(string Key, string ClassName, int Red, int Green, int Blue);
    
    public class DataProvider
    {
        public IEnumerable<MyData> Items => _items.AsEnumerable();
    
        public ValueTask<MyData?> GetDataAsync(string key)
            => ValueTask.FromResult( _items.FirstOrDefault(x => x.Key == key));
     
        private  List<MyData> _items = new()
        {
            new("red-products", "SO77439144.Components.Pages.Products", 255,0,0),
            new("green-products", "SO77439144.Components.Pages.Products", 0,255,0),
            new("blue-products", "SO77439144.Components.Pages.Products", 0,0,255),
        };
    }
    

    Registered as a service.

    The Products component:

    <h3>Products</h3>
    
    <div>
        <pre>Red : @Red</pre>
        <pre>Green : @Green</pre>
        <pre>Blue : @Blue</pre>
    </div>
    
    @code {
        [Parameter]
        public int Red { get; set; }
    
        [Parameter]
        public int Green { get; set; }
    
        [Parameter]
        public int Blue { get; set; }
    }
    

    And Index:

    @page "/"
    @page "/key/{Key}"
    @using System.Reflection
    @inject DataProvider Provider
    <PageTitle>Home</PageTitle>
    
    <h1>Hello, world!</h1>
    
    Welcome to your new app.
    @if (_componentType is not null)
    {
        <DynamicComponent Type="_componentType" Parameters="_componentProperties" />
    }
    
    @code {
        [Parameter] public string? Key { get; set; }
        private string? _key;
        private MyData? _data;
        private Dictionary<string, object> _componentProperties => new() {
            {"red", _data?.Red ?? 0},
            {"green", _data?.Green ?? 0},
            {"blue", _data?.Blue ?? 0},
        };
        private Type? _componentType;
    
        protected async override Task OnParametersSetAsync()
        {
            if (_key == this.Key)
                return;
    
            _key = this.Key;
    
            if (_key is not null)
            {
                _data = await Provider.GetDataAsync(_key);
                _componentType = this.GetComponentType(_data.ClassName);
            }
        }
    
        private Type? GetComponentType(string className)
        {
            var assembly = Assembly.GetExecutingAssembly();
            var instance =  assembly.CreateInstance(className);
            return instance?.GetType() ?? null;
        }
    }
    

    Paths are then https://localhost:7123/key/red-products etc.