aspnetcore: OnParameterSetAsync is triggered when using a CascadingParameter and NavigationManager

Describe the bug

I found something really strange within our project. It seems like OnParameterSetAsync does get triggered when you use the NavigateTo() method from the NavigationManager.

For example: In our project there is a class called AppMitarbeiter which stores some information about the user such as different names or ids. This class is being passed down from _Host.cshtml to App.razor and from App.razor to all other pages and components.

Within OnParameterSetAsync I do some validation of other parameters from a page. When something is incorrect I set an alert and navigate the user back to another page. This works fine.

However, I have another function on my site with saves some data and then navigate the user to another page. When this navigation is being raised, OnParameterSetAsync will be called again for the old page where I started the navigation. This results in an error for my validation in OnParameterSetAsnyc because this methods loads again the changed object and checks if it has been changed yet.

When I remove the cascaded Parameter from the component, everything works as it should except for I am missing my user information. I believe NavigateTo should not call OnParameterSetAsync again when the page is going to be switched.

To Reproduce

I created a small sample repo which can be found here: https://github.com/MarvinKlein1508/CascadingParameterDemo

To see what I mean put a debug point within AuftragStornieren.razor.cs in OnParameterSetAsync

Exceptions (if any)

— None ----

Further technical details

  • ASP.NET Core version 5.0.7 .NET SDK (gemäß “global.json”): Version: 6.0.100-preview.3.21202.5 Commit: aee38a6dd4

Laufzeitumgebung: OS Name: Windows OS Version: 10.0.19043 OS Platform: Windows RID: win10-x64 Base Path: C:\Program Files\dotnet\sdk\6.0.100-preview.3.21202.5\

Host (useful for support): Version: 6.0.0-preview.3.21201.4 Commit: 236cb21e3c

.NET SDKs installed: 3.1.400-preview-015203 [C:\Program Files\dotnet\sdk] 3.1.410 [C:\Program Files\dotnet\sdk] 5.0.100-rc.1.20452.10 [C:\Program Files\dotnet\sdk] 5.0.100 [C:\Program Files\dotnet\sdk] 5.0.103 [C:\Program Files\dotnet\sdk] 5.0.104 [C:\Program Files\dotnet\sdk] 5.0.201 [C:\Program Files\dotnet\sdk] 5.0.202 [C:\Program Files\dotnet\sdk] 5.0.204 [C:\Program Files\dotnet\sdk] 5.0.300-preview.21258.4 [C:\Program Files\dotnet\sdk] 5.0.301 [C:\Program Files\dotnet\sdk] 6.0.100-preview.3.21202.5 [C:\Program Files\dotnet\sdk]

.NET runtimes installed: Microsoft.AspNetCore.All 2.1.28 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All] Microsoft.AspNetCore.App 2.1.28 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 3.1.12 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 3.1.15 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 3.1.16 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 5.0.0-rc.1.20451.17 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 5.0.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 5.0.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 5.0.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 5.0.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 6.0.0-preview.3.21201.13 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.NETCore.App 2.1.28 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 3.1.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 3.1.15 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 3.1.16 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 5.0.0-rc.1.20451.14 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 5.0.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 5.0.4 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 5.0.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 5.0.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 6.0.0-preview.3.21201.4 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.WindowsDesktop.App 3.1.12 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 3.1.15 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 3.1.16 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 5.0.0-rc.1.20452.2 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 5.0.3 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 5.0.4 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 5.0.5 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 5.0.7 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 6.0.0-preview.3.21201.3 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

To install additional .NET runtimes or SDKs: https://aka.ms/dotnet-download

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 19 (8 by maintainers)

Most upvoted comments

Sorry it took such a long time to get this to the top of the investigation queue.

I have looked into this, and it is behaving like I would expect. The key thing that is causing trouble for you, I think, is having your <CascadingValue> inside the <Found> fragment of your router. This causes it to re-render each time a navigation occurs, which in turn sends a value notification to all descendant subscribers, which re-runs OnParametersSet in your component. Note that this happens before the <RouteView> re-renders, i.e., before the navigation to the new page (and the disposal of the old one) takes place.

I would recommend you change your App.razor component to put the <CascadingValue> outside the <Found> fragment, and then it won’t re-render and re-notify each time a new route is found. For example,

<CascadingValue Value="Mitarbeiter">
    <Router AppAssembly="@typeof(Program).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
            <FocusOnNavigate RouteData="@routeData" Selector="h1" />
        </Found>
        <NotFound>
            <PageTitle>Not found</PageTitle>
            <LayoutView Layout="@typeof(MainLayout)">
                <p>Sorry, there's nothing at this address.</p>
            </LayoutView>
        </NotFound>
    </Router>
</CascadingValue>

I still think that OnParameterSetAsync shouldn’t be called again for disposed components.

In my investigation, that isn’t what happens. The OnParameterSetAsync lifecycle method is called before the page component is disposed. The order of events is:

  1. User triggers navigation
  2. Router re-runs <Found> fragment
  3. In your example code, this re-renders the <CascadingValue> you had inside <Found>
  4. This sends an update notification to the existing page, invoking OnParameterSetAsync
  5. Then, <Found> continues rendering and now renders <RouteView>
  6. This finds the new page, renders it, and disposes the old one

… whereas if you put the <CascadingValue> outside <Found>, the order would be:

  1. User triggers navigation
  2. Router re-runs <Found> fragment
  3. <Found> renders <RouteView>
  4. This finds the new page, renders it, and disposes the old one

… and so nothing would be calling OnParameterSetAsync on the old page during the navigation.