【问题标题】:Calling Twilio Voice API with Blazor使用 Blazor 调用 Twilio 语音 API
【发布时间】:2020-12-16 19:22:18
【问题描述】:

我正在使用 blazor 服务器进行一个项目,我正在尝试使用 Twilio 进行语音通话。

我一直按照 twilio 的在线文档进行操作,但收到此错误:

System.Net.Http.HttpRequestException: Response status code does not indicate success: 404 (Not Found).
   at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()
   at QUBeMyGuest.Pages.GuestArrivals.EmergencyContact.GetClientToken() in C:\Pages\GuestArrivals\EmergencyContact.razor:line 98
   at QUBeMyGuest.Pages.GuestArrivals.EmergencyContact.OnAfterRenderAsync(Boolean firstRender) in C:\Users\\Pages\GuestArrivals\EmergencyContact.razor:line 58
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle)

文档说明我应该在我的解决方案中打开一个新的 asp.net core api 项目并将这个类添加到控制器文件夹中:

using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Twilio.Jwt;
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 = "xxxxxxxxxx";
        public readonly string AuthToken = "xxxxxxxx";
        public readonly string AppSid = "xxxxxxxx";
        public readonly string PhoneNumber = "xxxxxxxx";

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

然后我设置页面以使用我的 blazor 项目进行调用

@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://xxxxxxxxxxxxxxx";
    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; }
    }
}

然后添加了这个JS函数:

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

然后我在我的启动文件中添加了这个,但似乎没有什么不同:

 services.AddHttpClient();

            if (!services.Any(x => x.ServiceType == typeof(HttpClient)))
            {
                services.AddScoped<HttpClient>(s =>
                {
                    var uriHelper = s.GetRequiredService<NavigationManager>();
                    return new HttpClient
                    {
                        BaseAddress = new Uri(uriHelper.BaseUri)
                    };
                });
            }

关于我可能做错的任何建议?

【问题讨论】:

    标签: c# asp.net asp.net-core twilio blazor


    【解决方案1】:

    看到 404 时,首先应该想到的是一个不正确的 URL。由于 404 来自剃刀文件中的 GetClientToken 。这意味着您的 _tokenUrl 可能不正确。查看您的控制器,您的 URL 应该类似于 https://{host}/token/。您可能在文档中对链接进行了硬编码,同时它应该基于您的控制器。

    PS:HTTP 404 表示找不到请求的资源。熟悉其他 HTTP 响应代码,可能会为您节省大量调试时间。

    【讨论】:

    • 我必须为 api 项目使用 Ngrok 隧道。所以我在 _tokenUrl 中拥有的是https://4b4cjkaaf1b.ngrok.io/api/twiliobackend(api 是 asp 项目的名称),然后我还将这个地址存储在 Twilio 仪表板中
    • 从您的控制器中,您的 URL 应该看起来更像这样:4b4cjkaaf1b.ngrok.io/api/twillobackend/token 请注意在您的控制器中 GetToken 操作顶部设置的路由。 PS:当字符串作为参数传递到 HttpMethod 属性(如“HttpGet”)时。该字符串用作路线。它相当于“路线”属性
    • 是的,谢谢你,这就是现在对我有用的问题。但是我遇到了另一个问题..我可以进去打电话,但是我点击了应用程序的另一个部分,然后返回紧急联系人页面,我收到了这个错误:Error: Microsoft.JSInterop.JSException: Cannot read property 'setToken' of undefined TypeError: Cannot read property 'setToken' of undefined 如果我自动刷新页面然后一切正常。当我第二次进入页面时,我应该做些什么来刷新页面?
    • 此错误超出了您发布的代码的范围。您的代码是否托管在 Github 上?
    • 不,我在 github 上没有。所以有错误是别的东西而不是代码?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多