-
Notifications
You must be signed in to change notification settings - Fork 10.2k
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
Router incorrectly calls SetParametersAsync multiple times #44781
Comments
Thanks for contacting us. |
@Liero, can you please provide the minimal reproduction application as a publicly hosted GitHub repository? |
I've added my test project to github: https://github.com/Liero/Bug_Router_Querystring_SetParameters Please, investigate it. If I'm right, this is already causing a lot of nasty bugs to many users that have no idea, because it is hard to spot. It wasn't easy to track it down. |
Hello,
This is actually a big problem if you bind properties (marked with
The problem does not occur when using I've made a sample project: https://github.com/danm-de/BlazorSetParametersAsyncBug In the following picture you can see that the method |
We have the same problem as @Liero. The OnParameterSetAsync method is called right before navigating away even to another page under these circumstances:
|
@danm-de , @axylophon : upvote the original issue |
Having the same problem as @Liero, @danm-de or @axylophon Is there any info about investigation or planning of a fix? |
To learn more about what this message means, what to expect next, and how this issue will be handled you can read our Triage Process document. |
I have an issue when navigating from page that has property with [SupplyParameterFromQuery] attribute to another page that also has property with [SupplyParameterFromQuery] attribute - it causes the OnParametersSetAsync method to be called twice, any advice? |
To learn more about what this message means, what to expect next, and how this issue will be handled you can read our Triage Process document. |
I've come across this in a personal project recently when fiddling around with Blazor Wasm, and it's stumped me a bit. I'm not hugely familiar with the ASP.NET Core Razor component lifecycle, so this could very well be an intended functionality and this is just me making assumptions! I've got a minimal repro pushed up in a repository on my GitHub here 👉 https://github.com/CharlieJKendall/supply-parameter-from-query-bug Summary of the reproNavigating from a page that has a parameter decorated with Verbose client log output shows that there are in fact two distinct renders happening for the
|
.
There are then two types of issues:
|
Following on from the above, it would be great to get some clarity from the team around whether this is intentional or not. Trouble occurs when we make an HTTP request from within the The request fired on the first render returns the result set for page 1, and the request fired for the second render returns the result set for the expected page. If the continuation for the first request is executed after the continuation for the second request, then the incorrect data is displayed to the user. Query parameters are often optional, so |
This obviously isn't a proper solution, but I've had some success with a work around. I had the exact situation @CharlieJKendall described with incorrect data being displayed to the user. So far, the correct parameter state is always second. The following code at least ensures the proper parameter state is the last thing to process resulting in the proper data displayed to the user. The drawback is that I'm wasting time processing an incorrect parameter state. Plus, I have to wait for it to finish before I can process the correct parameter state. I look forward to a proper solution. Until then I'll take the performance sacrifice to ensure correct data.
|
Unfortunately there is no proper solution. This is a bug a there might be a workaround at best. My recommendation is: Don't use Following should work, but does not prevent from calling OnParametersSetAsync twice: protected override async Task OnParametersSetAsync()
{
await Task.Yield();
//parameter supplier from query attribute should be updated here
} if you are familiar with RX (see my blog post: MyComponent()
{
_parametersSet.Throttle(TimeSpan.FromMilliseconds(1))
.Select(_ => (SomeParameter, YourQueryStringParamter)
.DistinctUntilChanged()
.ObserveOn(SynchronizationContext.Current!)
.Subscribe(async _ =>
{
// do your async stuff here when one or both properties changes
StateHasChanged()
}
}
//put this into base class
private readonly Subject<Unit> _parametersSet = new ();
protected Observable<Unit> ParametersSet => _parametersSet.AsObservable()
public override async Task SetParametersAsync(ParameterView parameters)
{
await base.SetParametersAsync(parameters);
_parametersSet.OnNext(Unit.Default);
} |
You can try the following solution for: the Parameter for the target page is first null and then has the correct value. [SupplyParameterFromQuery]
public string ListType { get; set; }
protected override async Task OnParametersSetAsync()
{
if (string.IsNullOrWhiteSpace(ListType))
{
string[] uriParts = NavigationManager.Uri.Split("?");
string queryString = uriParts.Length > 1 ? uriParts[1] : string.Empty;
string queryListType = HttpUtility.ParseQueryString(queryString).Get(nameof(ListType));
if (!string.IsNullOrWhiteSpace(queryListType)) return;
} You can try the following solution for: The first time with the previous value Page=2, the second time with actual value Page=3 [SupplyParameterFromQuery]
public string ListType { get; set; }
protected override async Task OnParametersSetAsync()
{
string[] uriParts = NavigationManager.Uri.Split("?");
string queryString = uriParts.Length > 1 ? uriParts[1] : string.Empty;
string queryListType = HttpUtility.ParseQueryString(queryString).Get(nameof(ListType));
if (!string.Equals(ListType, queryListType, StringComparison.OrdinalIgnoreCase))
{
return;
} |
I'll add my problem to this pile as well, as it seems to be a possible side effect of the design of the Router based hierarchy where the downstream components are loading their params with a CascadingParameterAttributeBase derivative like the SupplyParameterFromQuery attribute. I have an example route /projects/1/files/?sk=2 , where:
When I navigate out of Files (/files) component to go up in the Project Details (/projects/1), by clicking for instance on a breadcrumb link, then the OnParametersSetAsync in the Files component is called and there is no way to tell who triggered it. This is obviously a big problem when API data is loaded in OnParametersSetAsync, making unnecessary HTTP calls. I need a solution for this common routing use case. It's not breaking, but it's a network and compute waste. Eventually, if handling the state change internally is not practical, I could work with some sort of a property on the Router OR maybe a source in the OnParametersSetAsync(object source) as in the good old days :D, that will allow me to manually manage the 'state change', if I want to, in the downstream components of a route. Thanks, |
I can repro this as well. For now, I'm back to using NavigationManager.LocationChanged + manual query string processing. |
I am facing this issue but my reproduction steps are slightly different. I am writing a tab control with steps very similar to described here. https://blazor-university.com/templating-components-with-renderfragements/creating-a-tabcontrol/ I am passing a @text variable to Tab's Text parameter (in the markup), so I am expecting the 'Text' of the tab to change when the value of @text changes However, when @text changes, and I call StateHasChanged on the tab control component, Blazor fires two SetParametersAsync events. Below is the sequence. On application load: @text - changed to "Test2" @text - changed to "Test3" Any idea what could be going wrong? Thanks very much |
As this is still an issue with OnNavigateAsync we removed it from our project and use the LocationChanged event of the NavigationManager instead. |
Great guys, instead of fixing infra problems you're focusing on AI bullshit. |
Good evening everyone, Im working with Blazor since 2021 (.Net 6) and had this issue (if it even is one) all the time. So what it is it catches the SetParametersAsync in a base class and when initiated all necessary parameters it runs a seperate "OnLoaded" and "OnLoadedAsync" method to prevent multiple calls. For parameters just add them to the list via the "AddParameterToCheck" method. I'll do this mostly within the OnInitialized method with a call like:
Cheers |
Is there an existing issue for this?
Describe the bug
WHEN I'm on
/index?queryparam=abc
and I click a link to/index/999
which is handled by the same component,THEN
SetParametersAsync
is called twice:This is causing a lot of issue when trying to load data based on parameters.
This only happens under specific circumstances:
OnNavigateAsync
handler on the RouterCascadingAuthenticationState
on top of the Router (default in blazor template)Expected Behavior
SetParametersAsync
should be called only once per single navigation eventSteps To Reproduce
/index?queryparam=abc
/999
linkExceptions (if any)
No response
.NET Version
6.0.400
Anything else?
.NET SDK (reflecting any global.json):
Version: 6.0.400
Commit: 7771abd614
Runtime Environment:
OS Name: Windows
OS Version: 10.0.22000
OS Platform: Windows
RID: win10-x64
Base Path: C:\Program Files\dotnet\sdk\6.0.400\
global.json file:
Not found
Host:
Version: 6.0.8
Architecture: x64
Commit: 55fb7ef977
The text was updated successfully, but these errors were encountered: