Skip to content
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

Using route constraints throws NullReferenceException when reloading multiple pages at the same time #17101

Closed
jaryn-kubik opened this issue Nov 14, 2019 · 3 comments
Assignees
Labels
area-blazor Includes: Blazor, Razor Components bug This issue describes a behavior which is not expected - a bug. Servicing-consider Shiproom approval is required for the issue
Milestone

Comments

@jaryn-kubik
Copy link

Describe the bug

I'm using custom reconnectionHandler in Blazor server-side to automatically reload a page when the connection is lost (like on server restart).

When I open two pages that have some route constraints (like @page "/{Id:int}") in two different tabs and do something that causes a server restart, both tabs reload at the same time and usually at least one fails with the following exception:

Error: System.NullReferenceException: Object reference not set to an instance of an object.
   at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
   at System.Collections.Generic.Dictionary`2.set_Item(TKey key, TValue value)
   at Microsoft.AspNetCore.Components.Routing.RouteConstraint.Parse(String template, String segment, String constraint)
   at Microsoft.AspNetCore.Components.Routing.TemplateSegment.<>c__DisplayClass0_0.<.ctor>b__0(String token)
   at System.Linq.Enumerable.SelectListPartitionIterator`2.ToArray()
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at Microsoft.AspNetCore.Components.Routing.TemplateSegment..ctor(String template, String segment, Boolean isParameter)
   at Microsoft.AspNetCore.Components.Routing.TemplateParser.ParseTemplate(String template)
   at Microsoft.AspNetCore.Components.RouteTableFactory.<>c.<Create>b__4_1(String v)
   at System.Linq.Enumerable.SelectArrayIterator`2.ToArray()
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at Microsoft.AspNetCore.Components.RouteTableFactory.Create(Dictionary`2 templatesByHandler)
   at Microsoft.AspNetCore.Components.RouteTableFactory.Create(IEnumerable`1 componentTypes)
   at Microsoft.AspNetCore.Components.RouteTableFactory.Create(IEnumerable`1 assemblies)
   at Microsoft.AspNetCore.Components.Routing.Router.SetParametersAsync(ParameterView parameters)
   at Microsoft.AspNetCore.Components.Rendering.ComponentState.SetDirectParameters(ParameterView parameters)
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewComponentFrame(DiffContext& diffContext, Int32 frameIndex)
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewSubtree(DiffContext& diffContext, Int32 frameIndex)
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InsertNewFrame(DiffContext& diffContext, Int32 newFrameIndex)
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForRange(DiffContext& diffContext, Int32 oldStartIndex, Int32 oldEndIndexExcl, Int32 newStartIndex, Int32 newEndIndexExcl)
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.ComputeDiff(Renderer renderer, RenderBatchBuilder batchBuilder, Int32 componentId, ArrayRange`1 oldTree, ArrayRange`1 newTree)
   at Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.RenderInExistingBatch(RenderQueueEntry renderQueueEntry)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()

To Reproduce

  1. download repo from https://github.com/jaryn-kubik/BlazorApp1 and launch the project
  2. open up the two example links in two different tabs
  3. do something that make VS rebuild the project (add something to a file and save it or whatever)
  4. wait a few seconds till the tabs try to automatically reload
  5. -> one of them should fail and throw an exception

There seems to be some race condition in the code handling constraints. If I remove the constraints and keep the route (@page "/{Id}" instead of @page "/{Id:int}") it works fine.

Further technical details

  • ASP.NET Core 3.0
  • Blazor server-side
@javiercn javiercn added the area-blazor Includes: Blazor, Razor Components label Nov 14, 2019
@javiercn
Copy link
Member

@jaryn-kubik thanks for contacting us and thanks for the repro project.

We'll take a look at it and get back to you.

@javiercn
Copy link
Member

javiercn commented Nov 15, 2019

I can repro this.

The issue is likely that this needs to be a concurrent dictionary: https://github.com/aspnet/AspNetCore/blob/master/src/Components/Components/src/Routing/RouteConstraint.cs#L12

@mkArtakMSFT the fix should be simple, we should likely patch this.

@javiercn javiercn added the bug This issue describes a behavior which is not expected - a bug. label Nov 15, 2019
@pranavkm pranavkm added this to the 3.1.0 milestone Nov 15, 2019
@pranavkm
Copy link
Contributor

@rynowak all yours

@danroth27 danroth27 added the Servicing-consider Shiproom approval is required for the issue label Nov 15, 2019
rynowak pushed a commit that referenced this issue Nov 15, 2019
Fixes: #17101

This changes the constraint cache to use ConcurrentDictionary. This code
is invoked in a multithreaded way in Blazor server resulting in internal
failures in dictionary.

Since this is a threading issue there's no good way to unit test it, but
I noticed we're missing tests in general for this class, so I added a
few for the caching behavior.
@dotnet dotnet locked as resolved and limited conversation to collaborators Dec 17, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-blazor Includes: Blazor, Razor Components bug This issue describes a behavior which is not expected - a bug. Servicing-consider Shiproom approval is required for the issue
Projects
None yet
Development

No branches or pull requests

5 participants