aspnetcore: [dotnet-sdk-8.0.100-rc.2.23451.1] SPOTClient reported Telerik.UI.for.Blazor package error on the login page.

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

When run the 3rd party application SPOTClient with the latest .NET 8 build, it failed on login page with Telerik.UI.for.Blazor package error.

Application Name: SPOTClient OS: Windows 10 21H2 CPU: X64 .NET Build Number: dotnet-sdk-8.0.100-rc.2.23451.1 App, App Source and Repro environment checking at: https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1881082

Verify Scenarios: 1). Windows 10 21H2 AMD64 + dotnet-sdk-8.0.100-rc.2.23451.1: Fail 2). Windows 10 21H2 AMD64 + dotnet-sdk-8.0.100-rc.1.23423.3: Pass 3). Windows 10 21H2 AMD64 + dotnet-sdk-6.0.414-win-x64: Pass

Expected Behavior

launch successful.

Steps To Reproduce

Minimal repro steps:
Please refer to the demo attached BlazorApp1.zip

  1. Create Blazor Server App project(.net7.0)
  2. Install the nuget package : telerik.ui.for.blazor
  3. Add this code to _Host.cshtml <script src="_content/Telerik.UI.for.Blazor/js/telerik-blazor.js" defer></script>
  4. Add this code to Index.razor
<div class="mb-3">
    <Telerik.Blazor.Components.TelerikTextBox Id="@ID" Value="@Values" Label="@Labels" PlaceHolder="Enter your connected email address"></Telerik.Blazor.Components.TelerikTextBox>
</div>

@code
{
    string Values = "Values", Labels = "Labels", ID = "1";
}
  1. Build and publish and run it with .net8 runtime
  2. Go to : http://localhost:5000/

App repro steps on repro machine: 1.Execute “cd C:\SPOTClient\App\SPOTClient” in cmd. 2.Execute “dotnet SPOT.Platform.Client.Host.dll” in cmd. 3.Launch Server url: https://localhost:5005

Exceptions (if any)

launch failed with below error:

blazor.server.js:1  [2023-09-05T08:32:55.677Z] Error: Microsoft.JSInterop.JSException: Maximum call stack size exceeded
RangeError: Maximum call stack size exceeded
    at Function.assign (<anonymous>)
    at e.extend (https://localhost:5005/_content/Telerik.UI.for.Blazor/js/telerik-blazor.js:1:9184)
    at t (https://localhost:5005/_content/Telerik.UI.for.Blazor/js/telerik-blazor.js:1:9537)
    at t (https://localhost:5005/_content/Telerik.UI.for.Blazor/js/telerik-blazor.js:1:9523)
    at t (https://localhost:5005/_content/Telerik.UI.for.Blazor/js/telerik-blazor.js:1:9523)
    at t (https://localhost:5005/_content/Telerik.UI.for.Blazor/js/telerik-blazor.js:1:9523)
    at t (https://localhost:5005/_content/Telerik.UI.for.Blazor/js/telerik-blazor.js:1:9523)
    at t (https://localhost:5005/_content/Telerik.UI.for.Blazor/js/telerik-blazor.js:1:9523)
    at t (https://localhost:5005/_content/Telerik.UI.for.Blazor/js/telerik-blazor.js:1:9523)
    at t (https://localhost:5005/_content/Telerik.UI.for.Blazor/js/telerik-blazor.js:1:9523)
   at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](Int64 targetInstanceId, String identifier, Object[] args)
   at Telerik.Blazor.Components.Common.TextBoxBase.InitJsComponentAsync()
   at Telerik.Blazor.Components.Common.TextBoxBase.OnAfterRenderInternalAsync(Boolean firstRender)
   at Telerik.Blazor.Components.Common.TextBoxBase.OnAfterRenderAsync(Boolean firstRender)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)

.NET Version

8.0.100-rc.2.23451.1

Anything else?

dotnet info:

.NET SDK:
 Version:   8.0.100-rc.2.23451.1
 Commit:    dabc29073d

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.22000
 OS Platform: Windows
 RID:         win-x64
 Base Path:   C:\Program Files\dotnet\sdk\8.0.100-rc.2.23451.1\

.NET workloads installed:
There are no installed workloads to display.

Host:
  Version:      8.0.0-rc.2.23431.9
  Architecture: x64
  Commit:       3c48925a6c
  RID:          win-x64

.NET SDKs installed:
  8.0.100-rc.2.23451.1 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 8.0.0-rc.2.23431.20 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 8.0.0-rc.2.23431.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 8.0.0-rc.2.23430.5 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Other architectures found:
  None

Environment variables:
  Not set

global.json file:
  Not found

Learn more:
  https://aka.ms/dotnet/info

Download .NET:
  https://aka.ms/dotnet/download

@dotnet-actwx-bot @dotnet/compat

About this issue

  • Original URL
  • State: closed
  • Created 10 months ago
  • Comments: 15 (8 by maintainers)

Most upvoted comments

Hi all,

My name is Stamo Gochev and I am one of the developers working on the Telerik UI for Blazor product.

I want to inform you that we are investigating the issue. Once we have more details, we will share our findings. If you have any further feedback or questions about the case, please reach out to us by opening a Telerik support ticket.

@SteveSandersonMS You can close the current issue as it is not related to the Blazor framework.

I’ve been trying to investigate, which is tricky, because this issue happens inside telerik-blazor.js which is not included in the repro sources, and the only publicly available versions of it are minified.

However I do think I can see what’s going on. telerik-blazor.js tries to do something similar to:

deepExtend(options1, options2)

… where options1 and options2 are both JavaScript objects that have a property called dotNetInstance of type DotNetObject. The deepExtend logic presumably walks all the properties of options2 recursively to apply them to options1.

In effect this means writing to the internals of a DotNetObject instance, which is definitely not supported. In .NET 7 and before, this happened to work, because both of the dotNetInstance objects happened to have the same _id value and no other properties. But in .NET 8, DotNetObject also has a new property _callDispatcher of type CallDispatcher, which on Blazor Server is actually the CircuitManager. This references a very wide range of things, and in particular, has a reference cycle so that if you naively try to walk its properties recursively, you’ll get stuck in an infinite loop evaluating:

_callDispatcher._dispatcher._dotNetCallDispatcher._dispatcher._dotNetCallDispatcher._dispatcher._dotNetCallDispatcher ... etc

Fixing this

Developers and component library authors shouldn’t be making the assumption that DotNetObject instances are safe to mutate internally (they are opaque handles, and mutating their internals is like private reflection or unsafe code in C#), nor should they assume it’s possible to walk their properties recursively (again, it’s exactly equivalent to using private reflection in C# to walk everything reachable from some framework primitive like GCHandle). It only worked by chance in earlier versions.

So, the best fix would be inside telerik-blazor.js, changing it to stop doing an infinite property traversal or any mutations on DotNetObject instances.

Stopping the problem more generally

Blazor could be more defensive about this. For example, we could change DotNetObject (in Microsoft.JSInterop.ts) so that its properties are not enumerable or at least have symbol names. As per the traversal rules, the options include:

  • Use symbol names to stop the properties showing up in for (let propName in obj). That’s what telerik-blazor.js is doing to enumerate the properties.
  • Or, define the property as nonenumerable. That’s a bit more robust but has a perf cost (and is still visible to getOwnPropertyNames/getOwnPropertySymbols)
  • Or even creating a special inheritance chain where _callDispatcher has a symbol name and is defined only on the prototype chain. That would give very high robustness against accidental discovery but is quite complex as we’d have to go outside the help that TypeScript offers natively for objects and inheritance
  • Or avoid the whole situation in the first place. Instead of having _callDispatcher on DotNetObject, replace it with a numeric ID into a Map<number, CallDispatcher>. Then it would be exactly equivalent to what we had before in terms of behavior when enumerating or assigning properties (for good or ill).

If we did this, I don’t know if telerik-blazor.js would start working. My guess is it probably would, at least in the common case where you only have either Server or WebAssembly in your app at a single time. If you have both platforms at once, or switch from one to the other, then it may be buggy since it appears to make the assumption it’s allowed to track a single DotNetObject that refers to .NET as a whole. I can’t confirm either way since I don’t have access to its sources or design documents etc.

If we had to work around it in Blazor (but hopefully it will be fixed inside telerik-blazor.js instead)

While I’m motivated to stop the property from appearing in enumeration (likely by just using a symbol name), the more risk-averse solution is replacing the new property with an ID, i.e., the fourth option on the set above.

Note that Virtualize.ts uses a hack to access the _id and _callDispatcher properties directly across library boundaries. No matter which option we choose, we would also have to do something else to make that continue to work. For example if we use symbol-named properties, we could expose the property name symbols intentionally from Microsoft.JSInterop, or expose a helper function that can supply the values of those properties. Not sure what reaction will be necessary if we replace the instance with a numeric ID.

Thanks @Stamo-Gochev. Closing this as external at this point, given no action is pending from our end.

Hi all,

My name is Stamo Gochev and I am one of the developers working on the Telerik UI for Blazor product.

I want to inform you that we are investigating the issue. Once we have more details, we will share our findings. If you have any further feedback or questions about the case, please reach out to us by opening a Telerik support ticket.

@SteveSandersonMS You can close the current issue as it is not related to the Blazor framework.

A quick update on this - we have a bug fix for the reported problem - if you are a Telerik customer and would like to test the fix, please open a Telerik support ticket and our team will help you.

@SteveSandersonMS We tried it with latest Telerik version, it is also reproduced. Here is the repro for your reference. BlazorApp_Telerik4.zip

Update the minimal repro steps as following:

  1. Create Blazor Server App project(.net7.0)
  2. Install the nuget package : telerik.ui.for.blazor.trial (https://www.telerik.com/try/ui-for-blazor)
  3. Add this code to _Host.cshtml
<script src="_content/Telerik.UI.for.Blazor.Trial/js/telerik-blazor.js" defer></script>
  1. Add this code to program.cs
builder.Services.AddTelerikBlazor();
  1. Add this code to Index.razor
<p>TextBox value: @StringValue</p>
<TelerikTextBox @bind-Value="@StringValue" />
@code {

    string StringValue { get; set; }

}
  1. Build and publish and run it with .net8 runtime
  2. Go to : http://localhost:5000/

@Junjun-zhao will be able to try using the latest Telerik version 4.5.0 tonight (team is based in China) and report back.

@Junjun-zhao did work as is with the earlier version of the .NET 8 (RC1 as an example) or just .NET 7?

Yes, it seems to have worked in RC1 based on the following at the top of the issue: Verify Scenarios: 1). Windows 10 21H2 AMD64 + dotnet-sdk-8.0.100-rc.2.23451.1: Fail 2). Windows 10 21H2 AMD64 + dotnet-sdk-8.0.100-rc.1.23423.3: Pass 3). Windows 10 21H2 AMD64 + dotnet-sdk-6.0.414-win-x64: **Pass**