无法在 Blazor 中收到承诺

Can not receive promise in Blazor

我正在通过 js Blazor 向服务器发送 POST 请求 interop.The post 请求到达服务器,经过计算,然后发回。 js 处理程序为承诺调用 resolve,但数据没有返回到 Blazor

JS 互操作

window.methods={
    submit: function () {
            return new Promise((resolve, reject) => {
                var form = document.getElementById("newTestForm");
                var data = new FormData(form);
                var xhr = new XMLHttpRequest();


                var method = form.getAttribute('method');
                var action = form.getAttribute('action');
                xhr.open(method, action);
                xhr.onload = function () {
                    if (xhr.status == 200) {
                        resolve(xhr.response); //data gets here in correct format !!!!!!!
                    }
                    else if (xhr.status != 200) {
                        reject("Failed to submit form with status" + xhr.status);
                    }
                }
                xhr.send(data);
            });
        }
}

控制器

[HttpPost]
[Route("/myroute")]
public async Task<string> ReturnData()
{
    await Task.Delay(1000);
    return "hello";
}

Blazor 组件

<form method="post" action="/myroute">
....some inputs
</form>
<button onclick="@SubmitAsync"></button>
@functions{
      public static async Task<string> SubmitNewTestAsync()
        {
            try
            {
                var data = await JSRuntime.Current.InvokeAsync<string>("methods.submit");

                return data;
            }
            catch (Exception ex)
            {

                throw;
            }

        }

     public async Task SubmitAsync()
     {
         string data= await SubmitNewTestAsync();
     }
}

响应正确,js方法submit对结果调用resolve。我首先认为这可能是反序列化问题。但它不会抛出任何错误。

我尝试了不同类型的响应(bytesobjectsstring),但仍然没有响应,也没有异常。

可能是什么问题?

P.S 我需要使用 XMLHttpRequest 因为我想保持在同一页面上。如果 Blazor 中存在异常,我应该会看到异常,因为我正在使用 Server-Side hosting

进行测试

更新

好吧,在尝试了很多事情之后,问题似乎出在 Blazor 方面,特别是在 JSRuntime.Current.InvokeAsync<Type> 方法中。
看来请求只会 finish 不返回任何东西(也不抛出任何错误)除非 Typeprimitive/object/dynamic. 如果这是 Blazor 特定的,我现在不这样做问题了。

例子

考虑以下模型:

[Serializeable]
public class MyType{
 public int value{get;set;}
}

这就是发生的事情(Blazor 端):

var data = await JSRuntime.Current.InvokeAsync<MyType>("methods.submit"); //fails
var data = await JSRuntime.Current.InvokeAsync<object>("methods.submit"); //works
var data = await JSRuntime.Current.InvokeAsync<dynamic>("methods.submit"); //works

到目前为止,还使用 ​​longintstring 进行了测试,它们都有效。 接收图元似乎没有问题。

这可能是使用已删除的静态 JSRuntime.Current 属性 的结果。相反,您应该将 IJSRuntime 注入到您的组件中:

@inject IJSRuntime JSRuntime;

public static async Task<string> SubmitNewTestAsync()
    {
        try
        {
            var data = await JSRuntime.InvokeAsync<string>("methods.submit");

            return data;
        }
        catch (Exception ex)
        {

            throw;
        }

    }

在您的 JavaScript 函数中试试这个代码片段:

xhr.onload = function () {
      if (this.status >= 200 && this.status < 300) {
        resolve(xhr.responseText);
      } else {
         reject("Failed to submit form with status" + xhr.status);
      }
    };

我对 Stripe 付款承诺有同样的问题。 Call .NET methods from JavaScript functions in ASP.NET Core Blazor looked like is good way to implement it. Then i found Blazor Javascript Interoperability 博客 post 巧妙地解决了问题。

这里只是一些指南,请阅读文章以了解概念。

Javascript

function WithPromise(promiseHandler) {
   var somePromise =  promise.then((value) => {
   promiseHandler.invokeMethodAsync('SetResult', JSON.stringify(value));    
}

承诺处理程序

public class PromiseHandler : IPromiseHandler
{   
    public TaskCompletionSource<string> tcs { get; set; }

    [JSInvokable]
    public void SetResult(string json)
    {
        // Set the results in the TaskCompletionSource
        tcs.SetResult(json);
    }
}

从 c# 调用一些函数

public Task<string> SomePromiseCall()
{
    var tcs = new TaskCompletionSource<string>();
    var promiseHandler = DotNetObjectReference.Create<PromiseHandler>(new PromiseHandler() { tcs = tcs });
    _jsRuntime.InvokeAsync<object>("WithPromise", promiseHandler);

    return tcs.Task;
}