I'm trying to connect Nexmo to a web socket when doing an inbound call (the user calls the number bought with nexmo and link to the app).
As of now, I'm simply trying this Sample Code (which simply echoes back what the caller says) and to connect to this websocket via Nexmo following the "documentation" Here.
I successfully send an action "connect" to nexmo. While calling the number bought with Nexmo, it properly redirects to the endpoint (api/nexmo/socket
), as shown when using breakpoints, but then it hangs up when reaching webSocket.ReceiveAsync in the Echo method.
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);
}
}
}
Here the exception that was caught :
System.Net.WebSockets.WebSocketException (0x80004005): The remote party closed the WebSocket connection without completing the close handshake. ---> System.Net.WebSockets.WebSocketException (0x80004005): The remote party closed the WebSocket connection without completing the close handshake.
More of the exception:
at System.Net.WebSockets.ManagedWebSocket.ThrowIfEOFUnexpected(Boolean throwOnPrematureClosure) at System.Net.WebSockets.ManagedWebSocket.EnsureBufferContainsAsync(Int32 minimumRequiredBytes, CancellationToken cancellationToken, Boolean throwOnPrematureClosure) at System.Net.WebSockets.ManagedWebSocket.ReceiveAsyncPrivate[TWebSocketReceiveResultGetter,TWebSocketReceiveResult](
Memory`1
payloadBuffer, CancellationToken cancellationToken, TWebSocketReceiveResultGetter resultGetter) at System.Net.WebSockets.ManagedWebSocket.ReceiveAsyncPrivate[TWebSocketReceiveResultGetter,TWebSocketReceiveResult](Memory`1
payloadBuffer, CancellationToken cancellationToken, TWebSocketReceiveResultGetter resultGetter) at ....Controllers.NexmoController.Echo(HttpContext context, WebSocket webSocket) in C:...\Controllers\NexmoController.cs:line 97 at ....Controllers.NexmoController.GetAudio() in 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 mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at System.Threading.Tasks.ValueTask`1.get_Result() at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync() at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync() at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync() at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter() at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync() at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Any ideas what went down? Or how I could fix this? I don't really understand what's the issue here.
I also tried to check the WebSocketState of the Websocket and it is set on "Open". For info, I tested the sample code (websocket echoing the user's input) on its own and it works.