【问题标题】:Blazor - JavaScript Interop - No .NET call dispatcher has been setBlazor - JavaScript 互操作 - 未设置 .NET 调用调度程序
【发布时间】:2020-10-20 13:58:07
【问题描述】:

我正在试验Blazor WebAssembly app。当我的页面(即 index.html)加载时,我想在加载时将一个 JavaScript 数组传递给 Blazor 应用程序。在尝试call a method from 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 的 UI。谢谢!

【问题讨论】:

    标签: c# blazor


    【解决方案1】:

    欢迎来到 Blazor!

    首先,我建议阅读Call .Net from js 的文档

    您在 index.html 中包含脚本的方式意味着,该脚本在您的 wasm 应用加载之前执行。

    为了解决这个问题,最好在 OnAfterRenderAsync 生命周期方法中使用 js 互操作 (Lifecycle docs)

    因此,如果您将脚本更新为:

    <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 还支持实例方法调用。你会在这里找到一个很好的例子Instance call

    最后,我不建议过多地触摸 index.html。创建和引用单独的 .js 文件或从 .NET 5 RC1 你可以使用Js isolation

    【讨论】:

      【解决方案2】:

      有一种方法可以确保在尝试调用互操作之前初始化 Blazor

      修改索引以防止 Blazor 自动加载

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

      然后你可以自己启动 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>
      

      【讨论】:

        【解决方案3】:

        // 我遇到的错误

        blazor.webassembly.js:1 Uncaught (in promise) 错误:没有 .NET 调用 调度员已设置。在 m (blazor.webassembly.js:1:2655) 在 h (blazor.webassembly.js:1:2548) 在 Object.e.invokeMethodAsync (blazor.webassembly.js:1:3389) 在 HTML 文档。 (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>
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-08-09
          • 2023-03-25
          • 2020-07-15
          • 2012-05-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-09-26
          相关资源
          最近更新 更多