无法在 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
。我首先认为这可能是反序列化问题。但它不会抛出任何错误。
我尝试了不同类型的响应(bytes
、objects
、string
),但仍然没有响应,也没有异常。
可能是什么问题?
P.S 我需要使用 XMLHttpRequest
因为我想保持在同一页面上。如果 Blazor 中存在异常,我应该会看到异常,因为我正在使用 Server-Side hosting
进行测试
更新
好吧,在尝试了很多事情之后,问题似乎出在 Blazor
方面,特别是在 JSRuntime.Current.InvokeAsync<Type>
方法中。
看来请求只会 finish 不返回任何东西(也不抛出任何错误)除非 Type
是 primitive
/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
到目前为止,还使用 long
、int
和 string
进行了测试,它们都有效。
接收图元似乎没有问题。
这可能是使用已删除的静态 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;
}
我正在通过 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
。我首先认为这可能是反序列化问题。但它不会抛出任何错误。
我尝试了不同类型的响应(bytes
、objects
、string
),但仍然没有响应,也没有异常。
可能是什么问题?
P.S 我需要使用 XMLHttpRequest
因为我想保持在同一页面上。如果 Blazor 中存在异常,我应该会看到异常,因为我正在使用 Server-Side hosting
更新
好吧,在尝试了很多事情之后,问题似乎出在 Blazor
方面,特别是在 JSRuntime.Current.InvokeAsync<Type>
方法中。
看来请求只会 finish 不返回任何东西(也不抛出任何错误)除非 Type
是 primitive
/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
到目前为止,还使用 long
、int
和 string
进行了测试,它们都有效。
接收图元似乎没有问题。
这可能是使用已删除的静态 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;
}