'Blazor - JavaScript Interop - No .NET call dispatcher has been set

I am experimenting with a Blazor WebAssembly app. When my page (i.e. index.html) loads, I want to pass a JavaScript array to the Blazor app when it loads. While trying to call a method from JavaScript, I've run into an error that says:

Uncaught (in promise) Error: No .NET call dispatcher has been set

My code looks like this:

index.html

<body>
    <app>Loading...</app>

    <div id="blazor-error-ui">
        An unhandled error has occurred.
        <a href="" class="reload">Reload</a>
        <a class="dismiss">🗙</a>
    </div>
    <script src="_framework/blazor.webassembly.js"></script>

    <script>
        let items = [
            { name:'Item 1', description:'This is a description of the first item' },
            { name:'Item 2', description:'This is a description of the second item' },
            { name:'Item 3', description:'This is a description of the third item' },
        ];

        try
        {
            DotNet
                .invokeMethodAsync('MyOrg.MyApp.Index', 'LoadItems')
                .then(results => {
                    console.log(results);
                })
            ;
        }
        catch (ex)
        {
            console.log(ex);
        }
    </script>
</body>

Index.razor

@page "/"

@using System.Threading.Tasks;    
@using Microsoft.Extensions.Logging;

@inject ILogger<Index> logger;

<p>
    Items loaded: <span>@items.Count</span>
</p>

@code {
    List<object> items = new List<object>();

    [JSInvokable]
    private Task LoadSnippets() 
    {
        try 
        {
            logger.LogInformation("Loading items...");
            items = new List<object>();
        }
        catch (Exception ex)
        {
            logger.LogError(ex, $"Failed to load items.");
        }
        return Task.CompletedTask;
    }
}

The first difference I noticed was that the example shown in the docs relied on a static method. Is this a requirement? If so, that would imply there's not a way to perform logging for example. Logging aside, even if I add static to the LoadItems method, I still get the error listed above. I don't understand why.

In short, I'm trying to create a "headless" Blazor app. I'd like to use the richness of C# to work with the data, I need to pass the results to the UI, which relies on HTML/CSS. Thank you!



Solution 1:[1]

There's a way to ensure Blazor is initialized before trying to call interop

Modify your index to prevent Blazor autoloading

<script src="_framework/blazor.webassembly.js" autoload="false"></script>

Then you can boot Blazor yourself and use a promise to execute your interop

<script>
    let items = [
        { name:'Item 1', description:'This is a description of the first item' },
        { name:'Item 2', description:'This is a description of the second item' },
        { name:'Item 3', description:'This is a description of the third item' },
    ];
    window.Blazor.start()
       .then(()=>DotNet.invokeMethodAsync('MyOrg.MyApp.Index', 'LoadItems'))
       .then(results => console.log(results))
       .catch(ex=>console.log(ex));
</script>

Solution 2:[2]

// Error I faced

blazor.webassembly.js:1 Uncaught (in promise) Error: No .NET call dispatcher has been set. at m (blazor.webassembly.js:1:2655) at h (blazor.webassembly.js:1:2548) at Object.e.invokeMethodAsync (blazor.webassembly.js:1:3389) at HTMLDocument. (CropHelper.js:73:12)

// Solution

<script>
    window.Blazor.start()          
        .then(function () {
            var fileref = document.createElement('script')
            fileref.setAttribute("type", "text/javascript")
            fileref.setAttribute("src", "js/CropHelper.js")
            if (typeof fileref != "undefined")
                document.getElementsByTagName("head")[0].appendChild(fileref)
        })
        .then(results => console.log(results))
        .catch(ex => console.log(ex));

</script>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Cédric Rup
Solution 2 Ayushi