C# ASP.NET Core Web Api Ошибка: Удаленная сторона закрыла соединение WebSocket, не завершив рукопожатие
Есть 3 разных проекта: клиент(консольное приложение), веб сервис(web api) и Azure функция. Клиент отправляет данные(конфиг своего пк) на web api через WebSocket, и возвращает значение в консоль. Также Web Api полученные данные должен отправить в Azure функцию. Все отлично работает, но если Azure функцию не запустить, то в консоле клиента возвращается ошибка: WebSocket, не завершив рукопожатие. Как исправить так, чтоб web api возвращал значение, даже если Azure функция не запущена?
Ошибка возникает в функции SendAzure, если HttpWebRequest не сработал(Azure функция не запущена).
WebApi:
[ApiController]
[Route("[controller]")]
public class WebSocketsController : ControllerBase
{
private readonly ILogger<WebSocketsController> _logger;
PCInfo info = new PCInfo();
public WebSocketsController(ILogger<WebSocketsController> logger)
{
_logger = logger;
}
[HttpGet("/ws")]
public async Task Get()
{
if (HttpContext.WebSockets.IsWebSocketRequest)
{
using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
_logger.Log(LogLevel.Information, "WebSocket connection established");
await Echo(webSocket);
}
else
{
HttpContext.Response.StatusCode = 400;
}
}
private async Task Echo(WebSocket webSocket)
{
var buffer = new byte[1024 * 4];
var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
string jsonStr = Encoding.UTF8.GetString(buffer);
info = JsonConvert.DeserializeObject<PCInfo>(jsonStr);
await SendAzure(jsonStr); //send Azure function
_logger.Log(LogLevel.Information, "Message received from Client");
while (!result.CloseStatus.HasValue)
{
var serverMsg = Encoding.UTF8.GetBytes($"Server: Hi! Client PC parameters: \n{info.pcName}\n{info.osName}\n{info.coreVersion}\n{info.timeZone}");
await webSocket.SendAsync(new ArraySegment<byte>(serverMsg, 0, serverMsg.Length), result.MessageType, result.EndOfMessage, CancellationToken.None);
_logger.Log(LogLevel.Information, "Message sent to Client");
result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
_logger.Log(LogLevel.Information, "Message received from Client");
}
await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
_logger.Log(LogLevel.Information, "WebSocket connection closed");
await SendAzure(jsonStr); //send Azure function
}
private async Task SendAzure(string str)
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(" http://localhost:7071/api/Function1");
req.Method = "POST";
req.ContentType = "application/json";
Stream stream = await req.GetRequestStreamAsync();
string json = str;
byte[] buffer = Encoding.UTF8.GetBytes(json);
await stream.WriteAsync(buffer, 0, buffer.Length);
HttpWebResponse res = (HttpWebResponse)req.GetResponse();
}
}
Ответы (1 шт):
HttpWebRequest устарел, давайте перепишем метод.
private static readonly HttpClient _localhostClient = new HttpClient() { DefaultRequestVersion = new Version(2, 0) };
private async Task<string> SendAzureAsync(string json)
{
using var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost:7071/api/Function1");
request.Content = new StringContent(json, Encoding.UTF8, "application/json");
using var response = await _localhostClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
if (!response.IsSuccessStatusCode)
{
// залогируйте $"{(int)response.StatusCode} {response.ReasonPhrase}" = например 404 Not Found
}
return await response.Content.ReadAsStringAsync();
}
Теперь во-первых, запрос стал асинхронным и не вешает поток сервера, во-вторых за счет одного клиента на все внутренние запросы и поддержки HTTP/2, оно и работать будет быстрее. Далее настройте поведение и таймауты по вкусу, еще можете использовать фабрику клиентов вместо статичного экземпляра.
Еще можно обернуть вызов в try-catch
try
{
string azureResponse = await SendAzureAsync(jsonStr);
}
catch (Exception ex)
{
// залогируйте ex.Message
}
А как правильно работать с вебсокетами, я уже показывал здесь.