Асинхронный запрос к серверу

353
24 июля 2021, 15:40

Я использую функцию Request для связи клиента с сервером. string result = settingsWindows.Request(settingsView.Address + ":" + settingsView.Port.ToString() + "/Users/ReturnUsers", "");

public string Request(string connectionString, string param)
        {
            string res = "";
            try
            {
                WebRequest request = WebRequest.Create("http://" + connectionString);
                request.Method = "POST"; // для отправки используется метод Post
                                         // данные для отправки
                string data = param;
                // преобразуем данные в массив байтов
                byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(data);
                // устанавливаем тип содержимого - параметр ContentType
                request.ContentType = "application/x-www-form-urlencoded";
                // Устанавливаем заголовок Content-Length запроса - свойство ContentLength
                request.ContentLength = byteArray.Length;
                //записываем данные в поток запроса
                using (Stream dataStream = request.GetRequestStream())
                {
                    dataStream.Write(byteArray, 0, byteArray.Length);
                }
                WebResponse response = request.GetResponse();
                using (Stream stream = response.GetResponseStream())
                {
                    using (StreamReader reader = new StreamReader(stream))
                    {
                        res = reader.ReadToEnd();
                    }
                }
                response.Close();
            }
            catch
            {
                res = "ERROR";
            }
            return res;
        }

Эта функция возвращает результат запроса. Когда адрес сервера указан верно, то все хорошо. Но когда неверно - то основной поток блокируется на строках

using (Stream dataStream = request.GetRequestStream())
{
       dataStream.Write(byteArray, 0, byteArray.Length);
}

после чего вылетает исключение. Я бы хотел как-то асинхронно выполнять данную функцию. Не до конца разобрался с async/await. Попробовал сделать

public async Task<string> Request(string connectionString, string param)
{
   ...
   using (Stream dataStream = await request.GetRequestStreamAsync())
   {
         dataStream.Write(byteArray, 0, byteArray.Length);
   }
   ...
}

но так вообще процесс блокируется намертво. Подскажите, пожалуйста, что можно еще попробовать?

Answer 1

Цель в принципе разобраться как сделать запрос или как сделать его асинхронным или как сделать асинхронный запрос именно с WebRequest?

Если нужно просто сделать асинхронный, то вот работающий код:

public async Task<CallResult> PutAsync<TRequest>(string url, TRequest request)
        {
            string reqJson = JsonConvert.SerializeObject(request); // user your XML serializer here instead
            var reqContent = new StringContent(reqJson, Encoding.UTF8, "application/json"); // and here use XML
            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Accept.Add(mediaTypeApplicationJson);                    
                HttpResponseMessage response = await client.PutAsync(url, reqContent);
                string message;
                if (response.IsSuccessStatusCode || response.Content == null)
                {
                    message = response.ReasonPhrase;
                }
                else
                {
                    string unparsedResponse = await response.Content.ReadAsStringAsync(); // handle error after it...
                }
                return new CallResult
                {
                    IsSuccessful = response.IsSuccessStatusCode,
                    Message = message,
                };
            }
        }

можно ещё упростить для строк:

 public async Task<HttpResponseMessage > PostAsync(string url, string request)
            {
                var reqContent = new StringContent(request, Encoding.UTF8, "application/xml"); // and here use XML
                using (var client = new HttpClient())
                {
                  mediaType = new MediaTypeWithQualityHeaderValue("application/xml");
          client.DefaultRequestHeaders.Accept.Add(mediaType);                    
                    HttpResponseMessage response = await client.PostAsync(url, reqContent);

                }
            }

Сделать его синхронным легко - убери async, await и вызови нужный метод client

Только учти, результатом работы метода не должен быть код ошибки. Если там ошибка, то бросай исключение. Если ошибка ожидаемая, то делай объект в который скажет что запрос не прошёл. Но не код ошибки в перемешку с валидными данными чтобы потом проверять if(result == "ERROR") { handle it } В случае с низкоуровневыми библиотеками (типа запросов) вообще нельзя подавлять исключения, только логгировать.

READ ALSO
Отправка email-сообщений при помощи C#

Отправка email-сообщений при помощи C#

Как при помощи C# отправить pdf себе на почту? У меня получилось найти только это(скрин снизу), но хотелось бы что-то актуальное

174
Маршалинг строки Unicode 32

Маршалинг строки Unicode 32

Атоловская "libfptr10so" в линуксе работает с 4-х байтовыми символами в строке - Unicode 32

197