HTTP i HTTPS kao komponenta

↑ Nazad

Omotač oko HttpClient. HTTPS ne traži ništa posebno: u BaseAddress upišeš https://..., a šifrovanje i provera sertifikata idu automatski.

HttpClientComponent.cs

using System.ComponentModel;

namespace WinFormsApp_test
{
    /// <summary>
    ///  HttpClient kao non-visual komponenta. https radi samo od sebe — dovoljno je https:// u BaseAddress.
    /// </summary>
    [ToolboxItem(true)]
    [DesignerCategory("Code")]
    [DefaultEvent(nameof(ResponseReceived))]
    [DefaultProperty(nameof(BaseAddress))]
    public class HttpClientComponent : Component
    {
        private HttpClient? _http;
        private readonly SynchronizationContext? _ui = SynchronizationContext.Current;

        public HttpClientComponent() { }

        public HttpClientComponent(IContainer container)
        {
            container.Add(this);
        }

        [Category("Connection"), Description("Npr. https://api.example.com/")]
        [DefaultValue("https://localhost/")]
        public string BaseAddress { get; set; } = "https://localhost/";

        [Category("Connection"), Description("Timeout zahteva u sekundama.")]
        [DefaultValue(30)]
        public int TimeoutSeconds { get; set; } = 30;

        [Category("Security"), Description("Prihvati i nevažeći/self-signed sertifikat. Samo za testiranje!")]
        [DefaultValue(false)]
        public bool AllowUntrustedCertificate { get; set; }

        [Category("Data")]
        public event EventHandler<string>? ResponseReceived;

        [Category("Data")]
        public event EventHandler<Exception>? RequestFailed;

        // HttpClient se pravi tek pri prvom zahtevu, kad su properties već postavljeni
        private HttpClient Http => _http ??= CreateClient();

        private HttpClient CreateClient()
        {
            var handler = new HttpClientHandler();
            if (AllowUntrustedCertificate)
                handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

            return new HttpClient(handler)
            {
                BaseAddress = new Uri(BaseAddress),
                Timeout = TimeSpan.FromSeconds(TimeoutSeconds),
            };
        }

        public async Task<string?> GetAsync(string path)
        {
            try
            {
                string body = await Http.GetStringAsync(path);
                Raise(() => ResponseReceived?.Invoke(this, body));
                return body;
            }
            catch (Exception ex)
            {
                Raise(() => RequestFailed?.Invoke(this, ex));
                return null;
            }
        }

        public async Task<string?> PostJsonAsync(string path, string json)
        {
            try
            {
                using var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");
                using var response = await Http.PostAsync(path, content);
                response.EnsureSuccessStatusCode();
                string body = await response.Content.ReadAsStringAsync();
                Raise(() => ResponseReceived?.Invoke(this, body));
                return body;
            }
            catch (Exception ex)
            {
                Raise(() => RequestFailed?.Invoke(this, ex));
                return null;
            }
        }

        private void Raise(Action a)
        {
            if (_ui != null) _ui.Post(_ => a(), null); else a();
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing) _http?.Dispose();
            base.Dispose(disposing);
        }
    }
}

Upotreba

private async void button1_Click(object sender, EventArgs e)
{
    await httpClientComponent1.GetAsync("api/status");
}

private void httpClientComponent1_ResponseReceived(object sender, string body)
{
    textBox1.Text = body;   // već na UI niti
}

Izvor: 04-http-i-https.md