#c# #blazor
#c# #blazor
Вопрос:
Я экспериментирую с приложением Blazor WebAssembly. Когда моя страница (т. е. index.html ) загружается, я хочу передать массив JavaScript в приложение Blazor при его загрузке. При попытке вызвать метод из JavaScript я столкнулся с ошибкой, которая гласит:
Uncaught (in promise) Error: No .NET call dispatcher has been set
Мой код выглядит так:
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;
}
}
Первое отличие, которое я заметил, заключалось в том, что пример, показанный в документах, основывался на static
методе. Это требование? Если это так, это будет означать, что, например, нет способа выполнить ведение журнала. Выход из системы, даже если я добавлю static
к LoadItems
методу, я все равно получаю ошибку, указанную выше. Я не понимаю, почему.
Короче говоря, я пытаюсь создать «безголовое» приложение Blazor. Я хотел бы использовать возможности C # для работы с данными, мне нужно передать результаты в пользовательский интерфейс, который использует HTML / CSS. Спасибо!
Ответ №1:
Добро пожаловать в Blazor!
Во-первых, я бы посоветовал прочитать документы при вызове.Net из js
Способ включения скрипта в ваш index.html означает, что скрипт выполняется до загрузки вашего приложения wasm.
Чтобы решить проблему, рекомендуется использовать js interop в методе жизненного цикла OnAfterRenderAsync (документы жизненного цикла)
Поэтому, если вы обновите свой скрипт до чего-то вроде:
<script>
netFromJs = {
staticCall: function () {
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('wasmprerender.Client', 'LoadItems')
.then(results => {
console.log(results);
});
}
catch (ex) {
console.log(ex);
}
}
}
</script>
Затем в вашем компоненте (страница также является компонентом) вы сможете сделать что-то вроде:
@inject IJSRuntime _js
@code {
static List<object> items = new List<object>();
[JSInvokable]
public static Task LoadItems()
{
try
{
Console.WriteLine("Loading items");
items = new List<object>();
}
catch (Exception ex)
{
}
return Task.CompletedTask;
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await _js.InvokeVoidAsync("netFromJs.static");
}
}
Чтобы ответить на ваше замечание об этом статическом вызове. Ваш пример работает со статическим вызовом метода, Blazor также поддерживает вызов метода экземпляра. Здесь вы найдете хороший пример вызова экземпляра
Наконец, я не рекомендую touch index.html слишком много. Создайте и ссылайтесь на отдельный файл .js или из .NET 5 RC1, вы можете использовать изоляцию Js
Ответ №2:
Есть способ убедиться, что Blazor инициализирован перед попыткой вызвать interop
Измените свой индекс, чтобы предотвратить автозагрузку Blazor
<script src="_framework/blazor.webassembly.js" autoload="false"></script>
Затем вы можете самостоятельно загрузить Blazor и использовать обещание для выполнения вашего взаимодействия
<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>
Комментарии:
1. Он работает в Windows, но не работает на Android.
Ответ №3:
// Ошибка, с которой я столкнулся
blazor.webassembly.js: 1 Не перехваченный (в обещании) Ошибка: диспетчер вызовов .NET не установлен. в m (blazor.webassembly.js: 1:2655) в h (blazor.webassembly.js:1:2548) на объекте.e.invokeMethodAsync (blazor.webassembly.js:1:3389) в HTMLDocument. (CropHelper.js:73:12)
// Решение
<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>