• ASP.NET Core Blazor WebAssembly 之 .NET JavaScript互调


    Blazor WebAssembly可以在浏览器上跑C#代码,但是很多时候显然还是需要跟JavaScript打交道。比如操作dom,当然跟angular、vue一样不提倡直接操作dom;比如浏览器的后退导航。反之JavaScript也有可能需要调用C#代码来实现一些功能,毕竟客户的需求是千变万化的,有的时候只能通过一些hack的手段来实现。

    .NET调用JavaScript函数

    使用JSRuntime.InvokeVoidAsync调用无返回值的JavaScript函数

    显然我们的.NET类库里不会有JavaScript内置的alert方法来显示提示,这里演示下如何调用JavaScript的alert方法:

    <h3>.net call javascript</h3>
    
    <button @onclick="CallJs">
        Call alert
    </button>
    
    @inject IJSRuntime jsRuntime
    @code {
        private void CallJs()
        {
            jsRuntime.InvokeVoidAsync("alert", "this message from .net runtime .");
        }
    }
    
    

    使用JSRuntime.InvokeVoidAsync调用具有返回值的JavaScript函数

    我们在JavaScript环境定义一个加法函数然后.NET这边调用拿到结果:

        <script>
            function add(a, b) {
                return a + b;
            }
        </script>
    

    注意:JavaScript代码要放到wwwroot/index.html页面上里,不能直接放在组件里。

    组件代码:

    <h3>.net call javascript</h3>
    
    sum: @sum
    
    <button @onclick="CallJs">
        Call Add
    </button>
    
    @inject IJSRuntime jsRuntime
    @code {
    
        private int sum = 0;
    
        private async void CallJs()
        {
            sum = await jsRuntime.InvokeAsync<int>("add", sum, 2);
            this.StateHasChanged();
        }
    }
    
    

    运行一下:

    JavaScript调用.NET方法

    JavaScript调用.NET静态方法

    JavaScript调用.NET静态方法比较简单,把静态方法加上[JSInvokable],然后在JavaScript环境使用DotNet对象直接call就行:
    定义.NET静态方法:

    
        [JSInvokable]
        public static string GetNow()
        {
            return DateTime.Now.ToString();
        }
    

    使用JavaScript调用GetNow:

      $(document).ready(
                setTimeout(() => {
                    $('#btn1').on('click', function () {
                        DotNet.invokeMethodAsync('BlazorWasmComponent', 'GetNow')
                            .then(data => {
                                alert(data);
                            });
                    })
                }, 10000)
            ); 
    

    由于Blazor渲染UI结束后按钮才会插入到dom树上,所以这里使用一个傻办法让绑定事件的JavaScript代码置后运行。
    运行一下:

    JavaScript调用组件里的方法

    JavaScript调用组件里的方法比较绕,其实还是通过一个静态方法作为入口,把实例方法绑定一个静态delegate,然后让这个静态方法去执行delegate。
    .NET代码:

    <h3>javascript call .net</h3>
    
    <button id="btn1">
       Js call .net
    </button>
    
    @inject IJSRuntime jsRuntime
    @code {
    
        [JSInvokable]
        public static string GetNow()
        {
            return Act("");
        }
    
        public static Func<string, string> Act;
    
        protected override void OnInitialized()
        {
            Act = GetNowInInstance;
            base.OnInitialized();
        }
    
        public string GetNowInInstance(string str)
        {
            return DateTime.Now.ToString();
        }
    }
    
    

    JavaScript代码:

     $(document).ready(
                setTimeout(() => {
                    $('#btn1').on('click', function () {
                        DotNet.invokeMethodAsync('BlazorWasmComponent', 'GetNow')
                            .then(data => {
                                alert(data);
                            });
                    })
                }, 10000)
            ); 
    

    运行一下:

    调用对象的方法

    Blazor还可以把.NET对象(引用)直接传递到JavaScript运行时来让JavaScript直接调用.NET对象的方法。

    总的来说大概分4步:

    1. 实例化.net对象
    2. DotNetObjectReference.Create方法把.NET对象包装
    3. 通过JSRuntime调用一个JavaScript方法把第二步生成的对象传递到JavaScript运行时
    4. 在JavaScript侧通过invokeMethodAsync方法调用.NET对象里的方法

    下面演示下把组件整个实例传递出去,然后调用里面的GetNowInInstance方法。

    .net代码:

    <h3>javascript call .net</h3>
    
    <button id="btn1">
        Js call .net
    </button>
    @implements IDisposable
    @inject IJSRuntime jsRuntime
    @code {
        IDisposable _objRef;
        protected async override Task OnInitializedAsync()
        {
            _objRef = DotNetObjectReference.Create(this);
            await jsRuntime.InvokeAsync<string>(
                "receiveNetObj",
               _objRef);
            base.OnInitialized();
        }
    
        [JSInvokable]
        public string GetNowInInstance()
        {
            return DateTime.Now.ToString();
        }
    
        public void Dispose()
        {
            _objRef?.Dispose();
        }
    }
    
    

    注意:把.NET对象传递到JavaScript运行时存在内存泄漏的风险,所以组件需要实现IDisposable接口,在Dispose方法内调用objRef的Dispose方法来释放内存。

    JavaScript代码:

            var _netObj = null;
    
            function receiveNetObj(obj) {
                _netObj = obj;
            }
    
            $(document).ready(
                setTimeout(() => {
                    $('#btn1').on('click', function () {
                        _netObj.invokeMethodAsync("GetNowInInstance").then(
                            r => alert(r)
                        );
                    })
                }, 10000)
            );
    

    运行一下:

    总结

    使用JSRuntime可以在.NET里调用JavaScript的方法,这些方法必须是全局的,也就是挂载在window对象上的。
    在JavaScript里调用.NET方法主要有两种:

    1. 通过DotNet方式调用.NET的静态方法
    2. 把.NET对象直接传递到JavaScript运行时来调用对象上的方法

    相关内容

    ASP.NET Core Blazor Webassembly 之 路由
    ASP.NET Core Blazor Webassembly 之 数据绑定
    ASP.NET Core Blazor Webassembly 之 组件
    ASP.NET Core Blazor 初探之 Blazor WebAssembly
    ASP.NET Core Blazor 初探之 Blazor Server

    关注我的公众号一起玩转技术

  • 相关阅读:
    使用fiddler对手机APP进行抓包
    接口功能测试
    API测试
    接口测试之接口api文档的重要性
    接口测试(基础知识)
    MonkeyRunner使用
    Android 压力测试工具Monkey
    MonkeyScript
    Jmeter和LoadRunner的区别
    http协议简介
  • 原文地址:https://www.cnblogs.com/kklldog/p/blazor-wasm-jsnetcall.html
Copyright © 2020-2023  润新知