'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 |
