我用Blazor服务器端做了一个网站。我使用Twilio Voice Api让用户能够拨打紧急电话。我已经能够成功地打电话了。当我离开页面,然后返回页面再次拨打电话时,我收到了这个错误:
Error: Microsoft.JSInterop.JSException: Cannot read property 'setToken' of undefined
TypeError: Cannot read property 'setToken' of undefined
at a.register (https://media.twiliocdn.com/sdk/js/client/v1.3/twilio.min.js:39:420)
at Function.setup (https://media.twiliocdn.com/sdk/js/client/v1.3/twilio.min.js:47:126)
at Object.setup (https://localhost:44320/js/tw.js:6:23)
at https://localhost:44320/_framework/blazor.server.js:8:31619
at new Promise (<anonymous>)
at e.beginInvokeJSFromDotNet (https://localhost:44320/_framework/blazor.server.js:8:31587)
at https://localhost:44320/_framework/blazor.server.js:1:20052
at Array.forEach (<anonymous>)
at e.invokeClientMethod (https://localhost:44320/_framework/blazor.server.js:1:20022)
at e.processIncomingData (https://localhost:44320/_framework/blazor.server.js:1:18006)
at Microsoft.JSInterop.JSRuntime.InvokeWithDefaultCancellation[T](String identifier, Object[] args)
at Microsoft.JSInterop.JSRuntimeExtensions.InvokeVoidAsync(IJSRuntime jsRuntime, String identifier, Object[] args)
at QUBeMyGuest.Pages.GuestArrivals.EmergencyContact.OnAfterRenderAsync(Boolean firstRender) in C:PagesGuestArrivalsEmergencyContact.razor:line 75
at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle)
我的api是
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Twilio.Jwt;
using Twilio.Jwt.AccessToken;
using Twilio.Jwt.Client;
using Twilio.TwiML;
using Twilio.Types;
using System.Net.Http;
namespace api.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class TwilioBackEndController : ControllerBase
{
public readonly string AccountSid = "xxxxxx";
public readonly string AuthToken = "xxxx";
public readonly string AppSid = "xxxxx";
public readonly string PhoneNumber = "xxxxx";
[HttpGet("token")]
public async Task<IActionResult> GetToken()
{
var scopes = new HashSet<IScope>
{
new OutgoingClientScope(AppSid),
new IncomingClientScope("tester")
};
var capability = new ClientCapability(AccountSid, AuthToken, scopes: scopes);
return await Task.FromResult(Content(capability.ToJwt(), "application/jwt"));
}
[HttpPost("voice")]
public async Task<IActionResult> PostVoiceRequest([FromForm] string phone)
{
var destination = !phone.StartsWith('+') ? $"+{phone}" : phone;
var response = new VoiceResponse();
var dial = new Twilio.TwiML.Voice.Dial
{
CallerId = PhoneNumber
};
dial.Number(new PhoneNumber(destination));
response.Append(dial);
return await Task.FromResult(Content(response.ToString(), "application/xml"));
}
}
}
我的紧急联系页面是:
@page "/guest/emergencycall"
@using System.ComponentModel.DataAnnotations
@inject HttpClient httpClient
@using Microsoft.Extensions.DependencyInjection
@using System.Net.Http
<EditForm Model="Input" OnValidSubmit="InitiatePhoneCall">
<DataAnnotationsValidator />
<ValidationSummary />
<p>
<label for="phoneNumber">Enter Phone Number:</label>
<InputText id="phoneNumber" @bind-Value="Input.PhoneNumber"></InputText>
<button type="submit" class="btn btn-primary" disabled="@IsDialDisabled">DIAL</button>
<button type="button" id="endBtn" class="btn btn-primary" disabled="@IsEndDisabled" @onclick="EndPhoneCall">END</button>
<button type="button" id="clearBtn" class="btn btn-primary" disabled="@IsClearDisabled" @onclick="ClearPhoneNumber">CLEAR</button>
</p>
</EditForm>
<hr />
@if (Logs.Count == 0)
{
<p>No Logs available yet</p>
}
else
{
<ul>
@foreach (var log in Logs)
{
<li>@log</li>
}
</ul>
}
@code {
private string _tokenUrl = "https://4b4cd1derdsb.ngrok.io/api/twiliobackend";
private bool appSetupRun = false;
protected bool IsDialDisabled { get; set; } = false;
protected bool IsEndDisabled { get { return !IsDialDisabled; } }
protected bool IsClearDisabled { get { return string.IsNullOrEmpty(Input.PhoneNumber); } }
protected List<string> Logs { get; set; } = new List<string>();
protected InputModel Input { get; set; } = new InputModel();
[Inject]
protected IJSRuntime JSRuntime { get; set; }
[Inject]
protected IHttpClientFactory HttpClientFactory { get; set; }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender && !appSetupRun)
{
var token = await GetClientToken();
await JSRuntime.InvokeVoidAsync("appFunctions.setup", token);
appSetupRun = true;
}
}
protected async Task InitiatePhoneCall()
{
IsDialDisabled = true;
await LogMessage($"Calling the number {Input.PhoneNumber}");
await JSRuntime.InvokeVoidAsync("appFunctions.placeCall", Input.PhoneNumber);
await LogMessage($"Called the number {Input.PhoneNumber}");
StateHasChanged();
}
protected async Task EndPhoneCall()
{
IsDialDisabled = false;
await LogMessage($"Ending the call to {Input.PhoneNumber}");
await JSRuntime.InvokeVoidAsync("appFunctions.endCall");
await LogMessage($"Ended the call to {Input.PhoneNumber}");
StateHasChanged();
}
protected async Task ClearPhoneNumber()
{
await LogMessage("Clearing the phone number entry");
Input.PhoneNumber = string.Empty;
await LogMessage("Cleared the phone number entry");
StateHasChanged();
}
private async Task<string> GetClientToken()
{
var uri = new Uri(_tokenUrl);
using var client = HttpClientFactory.CreateClient();
var response = await client.GetAsync(uri);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
[JSInvokable]
public async Task LogMessage(string message)
{
Logs.Add($"{DateTimeOffset.Now} - {message}");
await Task.CompletedTask;
}
public class InputModel
{
[Required]
[Phone(ErrorMessage = "Please enter your phone number in a proper format")]
public string PhoneNumber { get; set; }
}
}
和我的javascript:
window.appFunctions = {
setup: function (token) {
console.log('Getting connected');
// Setup Twilio Device
Twilio.Device.setup(token);
Twilio.Device.ready(() => {
console.log('We are connected and ready to do the thing');
});
Twilio.Device.error((err) => {
console.error('This should not have been reached. We need to do something here');
console.error(err);
});
},
placeCall: function (destination) {
console.log(`Calling ${destination}`);
Twilio.Device.connect({ phone: destination });
console.log(`Successfully called ${destination}`);
},
endCall: function () {
console.log('Ending the call');
Twilio.Device.disconnectAll();
console.log('Successfully ended the call');
}
};
任何建议都将是伟大的
根据我的经验当Microsoft.JSInterop.JSException发生时,它通常来自于您调用javascript时在您的代码中,请验证从JSRuntime 调用的javascript函数
[Inject]
protected IJSRuntime JSRuntime { get; set; }
...
await JSRuntime.InvokeVoidAsync("appFunctions.setup", token);
await JSRuntime.InvokeVoidAsync("appFunctions.placeCall", Input.PhoneNumber);
await JSRuntime.InvokeVoidAsync("appFunctions.endCall");
becuasesetToken关键字始终用于web和api之间的通信设置的函数名。我猜在javascript函数appFunctions.setup中,一些对象在返回页面后变为null,因此无法初始化。正如你在中看到的
TypeError: Cannot read property 'setToken' of undefined
at a.register (https://media.twiliocdn.com/sdk/js/client/v1.3/twilio.min.js:39:420)
at Function.setup (https://media.twiliocdn.com/sdk/js/client/v1.3/twilio.min.js:47:126)
at Object.setup (https://localhost:44320/js/tw.js:6:23)
文件tw.js中的javascript函数(可能是第23行?(将使用一些null对象来设置communication?