无法在Blazor中获得承诺

时间:2019-05-05 15:48:39

标签: promise interop blazor

我正在通过js互操作从POST向服务器发送一个Blazor请求。发布请求到达服务器,经过计算,然后发回。 js处理程序调用{​​{1}}以获得承诺,但数据不会返回到resolve

JS Interop

Blazor

控制器

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

Blazor组件

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

响应正确,并且js方法<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(); } } 对结果调用submit。我首先认为这可能是反序列化问题。但这不会引发任何错误。

我尝试了不同类型的响应(resolvebytesobjects),但仍然没有响应,也没有例外。

可能是什么问题?

PS ,因为我要停留在同一页面上,因此需要使用string。自从我使用XMLHttpRequest

进行测试以来,我应该看到Blazor中是否存在异常。

更新

好的,因此在尝试了许多事情之后,问题似乎出在Server-Side hosting方面,特别是在Blazor方法中。
似乎请求将完成而没有返回任何内容(也不会引发任何错误),除非JSRuntime.Current.InvokeAsync<Type>Type / primitive / object,如果这不再是dynamic. 的特定问题,我现在就不这样做。 / p>

示例

考虑以下模型:

Blazor

这就是发生的事情(布拉泽尔一侧):

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

到目前为止,还使用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 longint进行了测试,它们都可以工作。 接收原语似乎没有问题。

2 个答案:

答案 0 :(得分:2)

这可能是使用已删除的静态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);
      }
    };

答案 1 :(得分:1)

我对Stripe付款承诺有同样的问题。 Call .NET methods from JavaScript functions in ASP.NET Core Blazor看起来是实现它的好方法。然后,我发现Blazor Javascript Interoperability博客文章很好地解决了问题。

这里只是一些准则,请在本文中休闲以了解概念。

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