Данный пример хорош тем, что ты можешь очень быстро создать ещё хоть 10 разных методов для обращения к API сервера. Часть кода была взята со справки майкрософта, частично модифицирована (где XML комментарии на английском).
HttpClientExample.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>
</Project>
Точка входа в приложение и основной алгоритм по получению данных в цикле.
Program.cs
using System;
using System.Threading;
using System.Threading.Tasks;
namespace HttpClientExample
{
class Program
{
// В качестве исключения я расположил в самом верху класса метод Main,
// обычно здесь должны быть поля класса, а все методы ниже.
#region Entry point
static async Task Main(string[] args)
{
var program = new Program();
await program.Run(args);
}
#endregion
private readonly SomeClient _client;
public Program()
{
_client = new SomeClient("http://localhost:5000");
}
private async Task Run(string[] args)
{
bool success = false;
do
{
try
{
// CancellationToken пригодится в приложениях с UI, где нужно, например,
// закрыть окно или уйти со страницы не дожидаясь, пока запрос отработает.
// Здесь заранее это заложено, можно и не использовать, если приложение консольное.
string data = await _client.GetData(CancellationToken.None);
success = true;
Console.WriteLine(data);
}
catch (ApiException ex)
{
// Одна реакция
Console.WriteLine(ex);
Console.WriteLine();
}
catch (Exception ex)
{
// Другая реакция
Console.WriteLine(ex);
Console.WriteLine();
}
await Task.Delay(150);
} while (!success);
_client.Dispose();
}
}
}
SomeClient.cs
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace HttpClientExample
{
public class SomeClient : IDisposable
{
private const string GET_TEXT_PART = "/api/system/get-text";
private const string GET_USER_PART = "/api/system/get-user";
private HttpClient _httpClient;
public Dictionary<string, string> DefaultHeaders { get; }
public SomeClient(string baseAddress)
{
var httpHandler = new HttpClientHandler
{
AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip
};
_httpClient = new HttpClient(httpHandler)
{
BaseAddress = new Uri(baseAddress)
};
DefaultHeaders = new Dictionary<string, string>
{
["Accept"] = "*/*",
["Accept-Encoding"] = "gzip, deflate",
["Cache-Control"] = "no-cache",
["Connection"] = "keep-alive",
};
}
public void Dispose()
{
if (_httpClient != null)
{
_httpClient.Dispose();
_httpClient = null;
GC.SuppressFinalize(this);
}
}
public async Task<string> GetData(CancellationToken cancellationToken)
{
string text = await InvokeText(HttpMethod.Get, GET_TEXT_PART, cancellationToken);
// Возможно, что-то залогировал.
return text;
}
public async Task<User> GetUser(CancellationToken cancellationToken)
{
var user = await InvokeJson<User>(HttpMethod.Get, GET_USER_PART, cancellationToken);
// Возможно, что-то залогировал.
return user;
}
/// <summary>
/// Sets the request.
/// </summary>
/// <param name="request">The request.</param>
/// <param name="requestContent">Content of the request.</param>
private void SetRequest(HttpRequestMessage request, object requestContent)
{
foreach (var header in DefaultHeaders)
{
request.Headers.Add(header.Key, header.Value);
}
if (requestContent != null)
{
request.Content = new StringContent(JsonConvert.SerializeObject(requestContent),
Encoding.UTF8,
Constants.HttpMimeTypes.JsonContentType);
}
}
/// <summary>
/// Invokes the specified HTTP method.
/// </summary>
/// <param name="httpMethod">The HTTP method.</param>
/// <param name="relativeUrl">The relative URL.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <param name="requestContent">Content of the request.</param>
/// <returns>instance of the type T</returns>
/// <exception cref="ApiException"></exception>
private async Task<string> InvokeText(HttpMethod httpMethod, string relativeUrl, CancellationToken cancellationToken, object requestContent = null)
{
using (var request = new HttpRequestMessage(httpMethod, relativeUrl))
{
SetRequest(request, requestContent);
using (HttpResponseMessage response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseContentRead, cancellationToken))
{
string responseText = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
return responseText;
}
throw new ApiException(response.StatusCode, responseText);
}
}
}
/// <summary>
/// Invokes the specified HTTP method.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="httpMethod">The HTTP method.</param>
/// <param name="relativeUrl">The relative URL.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <param name="requestContent">Content of the request.</param>
/// <returns>instance of the type T</returns>
/// <exception cref="ApiException"></exception>
private async Task<T> InvokeJson<T>(HttpMethod httpMethod, string relativeUrl, CancellationToken cancellationToken, object requestContent = null)
{
using (var request = new HttpRequestMessage(httpMethod, relativeUrl))
{
SetRequest(request, requestContent);
using (HttpResponseMessage response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseContentRead, cancellationToken))
{
string responseText = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
var resource = JsonConvert.DeserializeObject<T>(responseText);
return resource;
}
throw new ApiException(response.StatusCode, responseText);
}
}
}
private static class Constants
{
public static class HttpMimeTypes
{
/// <summary>
/// The json content type
/// </summary>
public const string JsonContentType = "application/json";
}
}
}
}
Этот класс используется просто для примера, как преобразовать JSON, полученный от сервера в экземпляр класса
User.cs
using Newtonsoft.Json;
namespace HttpClientExample
{
public class User
{
[JsonProperty("id", Required = Required.Always)]
public long Id { get; set; }
[JsonProperty("name", Required = Required.Always)]
public string Name { get; set; }
}
}
async await, чтобы было примепрное понимание, что происходит.
Скриншот сделан с видео:
https://youtu.be/lh8cT6qI-nA?t=1123