首页 > 解决方案 > 在 .Net Core 中将 Nexmo 连接到 Websocket 失败(远程方关闭了 WebSocket)

问题描述

我正在尝试在进行入站呼叫时将Nexmo连接到 Web 套接字(用户拨打使用 nexmo 购买的号码并链接到应用程序)。

到目前为止,我只是在尝试这个示例代码(它只是回应调用者所说的话)并按照“文档” Here之后通过 Nexmo 连接到这个 websocket 。

我成功地向 nexmo 发送了一个动作“连接”。在调用使用 Nexmo 购买的号码时,它会正确重定向到端点 ( ),如使用断点时所示,但在 Echo 方法中到达webSocket.ReceiveAsyncapi/nexmo/socket时它会挂断。

    using System;
    using System.Net.WebSockets;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using Newtonsoft.Json.Linq;

    namespace MyProject.Web.Controllers
    {
        [Route("api/[controller]")]
        [ApiController]
        public class NexmoController : ControllerBase
        {
            private WebSocket _webSocket;

            [HttpGet("answer")]
            public IActionResult AnswerHandler()
            {
                const string host = "MY_NGROK_URL";
                const string locale = "fr-FR";

                var nccos = new JArray();
                var nccoConnect = new JObject()
                {
                    { "action", "connect" },
                    { "endpoint", new JArray(new JObject{
                            { "type", "websocket" },
                            { "uri", $"wss://{host}/api/nexmo/socket"},
                            { "content-type", "audio/l16;rate=16000"},
                            { "headers", new JObject {
                                    { "language", locale },
                                    { "callerID", "MY_NUMBER_HARDCODED_WHILE_TESTING" }
                                }
                            }
                        })
                    }
                };
                nccos.Add(nccoConnect);
                return Content(nccos.ToString(), "application/json");
            }

            [HttpPost("event")]
            public IActionResult EventHandler()
            {
                return Ok();
            }

            [HttpGet("socket")]
            public async Task GetAudio()
            {
                if (HttpContext.WebSockets.IsWebSocketRequest)
                {
                    _webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
                    await Echo(HttpContext, _webSocket);
                }
                else
                {
                    HttpContext.Response.StatusCode = 400;
                }
            }

            //Copy Paste from the Sample Code
            private async Task Echo(HttpContext context, WebSocket webSocket)
            {
                var buffer = new byte[1024 * 4];
                //Breakpoint : ReceiveAsync generates an exception
                WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                while (!result.CloseStatus.HasValue)
                {
                    await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);

                    result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                }
                await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
            }
        }
    }

这里被捕获的异常:

System.Net.WebSockets.WebSocketException (0x80004005):远端没有完成关闭握手就关闭了WebSocket连接。---> System.Net.WebSockets.WebSocketException (0x80004005):远端没有完成关闭握手就关闭了WebSocket连接。

更多例外:

在 System.Net.WebSockets.ManagedWebSocket.ThrowIfEOFUnexpected(Boolean throwOnPrematureClosure) 在 System.Net.WebSockets.ManagedWebSocket.EnsureBufferContainsAsync(Int32 minimumRequiredBytes, CancellationTokencancellationToken, Boolean throwOnPrematureClosure) 在 System.Net.WebSockets.ManagedWebSocket.ReceiveAsyncPrivate[TWebSocketReceiveResultGetter,TWebSocketReceiveResult](Memory`1 在 System.Net.WebSockets.ManagedWebSocket.ReceiveAsyncPrivate[TWebSocketReceiveResultGetter,TWebSocketReceiveResult](Memory`1 payloadBuffer, CancellationToken cancelToken, TWebSocketReceiveResultGetter resultGetter) at ....Controllers.NexmoController.Echo(HttpContext context, WebSocket webSocket) in C:...\Controllers\NexmoController.cs:line 97 at ....Controllers.NexmoController.GetAudio () 在 C:...\Controllers\NexmoController.cs:line 68 at lambda_method(Closure , Object) at Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult() at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.AwaitableResultExecutor .Execute(IActionResultTypeMapper 映射器,ObjectMethodExecutor 执行器,对象控制器,Object[] 参数)在 Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync() 的 System.Threading.Tasks.ValueTask`1.get_Result() 在 Microsoft.AspNetCore。 Mvc.内部。ControllerActionInvoker.InvokeNextActionFilterAsync() 在 Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) 在 Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) 在 Microsoft.AspNetCore .Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync() 在 Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter() 在 Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context) 在 Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync() 的 Microsoft.AspNetCore.Mvc.Internal 的 .Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)。ResourceInvoker.InvokeAsync()
在 Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext) 在 Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext) 在 Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context) 在 Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware .Invoke(HttpContext 上下文)

有什么想法吗?或者我该如何解决这个问题?我真的不明白这里有什么问题。

我还尝试检查 Websocket 的 WebSocketState 并将其设置为“打开”。有关信息,我自己测试了示例代码(websocket 回显用户的输入)并且它可以工作。

标签: c#asp.net-corewebsocketphone-callnexmo

解决方案


我们找到了解决方案:

  • ngrock不适用于 websockets(不是免费的),所以我们在 azure 上发布了我们的应用程序。
  • 我们需要在StartUp中而不是在我们的控制器中实例化 websocket(如原始帖子中列出的示例代码)。我们将“Echo”方法放在另一个类中(为了保持良好的结构更是如此)并将其设置为静态。

现在一切正常:)

澄清:ngrock不适用于安全的 websockets (wss)


推荐阅读