简体   繁体   English

Blazor - JavaScript Interop - 没有设置 .NET 呼叫调度员

[英]Blazor - JavaScript Interop - No .NET call dispatcher has been set

I am experimenting with a Blazor WebAssembly app .我正在试验Blazor WebAssembly 应用程序 When my page (ie index.html) loads, I want to pass a JavaScript array to the Blazor app when it loads.当我的页面(即 index.html)加载时,我想在加载时将 JavaScript 数组传递给 Blazor 应用程序。 While trying to call a method from JavaScript , I've run into an error that says:在尝试从 JavaScript 调用一个方法时,我遇到了一个错误:

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

My code looks like this:我的代码如下所示:

index.html 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 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.我注意到的第一个区别是文档中显示的示例依赖于static方法。 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.除了登录,即使我将static添加到LoadItems方法,我仍然会收到上面列出的错误。 I don't understand why.我不明白为什么。

In short, I'm trying to create a "headless" Blazor app.简而言之,我正在尝试创建一个“无头” Blazor 应用程序。 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.我想使用 C# 的丰富性来处理数据,我需要将结果传递给依赖 HTML/CSS 的 UI。 Thank you!谢谢!

Welcome to Blazor!欢迎来到 Blazor!

Firstly, I would suggest reading the docs at Call .Net from js首先,我建议从 js阅读Call .Net 上的文档

The way you include the script in your index.html means, that the script is executed before your wasm app is loaded.您在 index.html 中包含脚本的方式意味着脚本您的 wasm 应用程序加载之前执行。

To solve the issue, it is a good practice to use js interop in OnAfterRenderAsync lifecycle method ( Lifecycle docs )为了解决这个问题,在 OnAfterRenderAsync 生命周期方法( Lifecycle docs )中使用 js interop 是一个很好的做法

So if you update your script to something like:因此,如果您将脚本更新为以下内容:

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

Then in your component (page is also component), you will be able to do something like:然后在您的组件(页面也是组件)中,您将能够执行以下操作:

@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");
    }
}

To address your note about that the static call.解决您关于静态调用的注释。 Your example works with the Static method call, Blazor also supports the Instance method call.您的示例适用于静态方法调用,Blazor 还支持实例方法调用。 You will find a nice example here Instance call你会在这里找到一个很好的例子实例调用

Lastly, I do not recommend touch index.html too much.最后,我不太推荐 touch index.html。 Create and reference separate .js file or from .NET 5 RC1 you can use Js isolation创建和引用单独的 .js 文件或从 .NET 5 RC1 您可以使用Js 隔离

There's a way to ensure Blazor is initialized before trying to call interop有一种方法可以确保在尝试调用互操作之前初始化 Blazor

Modify your index to prevent Blazor autoloading修改索引以防止 Blazor 自动加载

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

Then you can boot Blazor yourself and use a promise to execute your interop然后你可以自己启动 Blazor 并使用 promise 来执行你的互操作

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

// Error I faced // 我遇到的错误

blazor.webassembly.js:1 Uncaught (in promise) Error: No .NET call dispatcher has been set. 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.在 m (blazor.webassembly.js:1:2655) 在 h (blazor.webassembly.js:1:2548) 在 Object.e.invokeMethodAsync (blazor.webassembly.js:1:3389) 在 HTMLDocument。 (CropHelper.js:73:12) (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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何查看Blazor是否设置了属性? - How to check if a property has been set in Blazor? 可以在Blazor中将ElementRef属性设置为javascript互操作返回值吗? - Can ElementRef property be set to a javascript interop return value in Blazor? Blazor JS Interop 调用混乱 - Blazor JS Interop call confusion Blazor Javascript 互操作返回 Null - Blazor Javascript Interop Returns Null blazor 服务器端的 Javascript 互操作处理问题 - Javascript Interop Dispose Problem with blazor serverside Radzen Blazor WASM JavaScript 互操作 function 未定义 - Radzen Blazor WASM JavaScript Interop function not defined 响应已启动 Blazor 中的 HttpContext.SignOutAsync() 方法调用已引发异常 - Response already started Exception has been thrown on HttpContext.SignOutAsync() method call in Blazor Blazor 本地化的工作方式是否发生了变化? - Has there been a change in how Blazor localization works? Blazor 使用 Blazor 拍摄视频 Stream/使用 javascript 与 javascript 交互 - Blazor Take Snapshot of Video Stream with Blazor/ Interact with javascript using Blazor Interop 对Microsoft.Office.Interop.Excel的COM组件的调用已返回错误HRESULT E_FAIL - Error HRESULT E_FAIL has been returned from a call to a COM component for Microsoft.Office.Interop.Excel
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM