مقدمة: لماذا تحتاج إلى عميل HTTP صحيح في C#؟
في التطوير الحديث، لا يكاد أي تطبيق يستغني عن التفاعل مع الخدمات الخارجية. سواء كان إرسال البيانات إلى الخادم، أو الحصول على أسعار العملات، أو العمل مع API سحابي — كل هذا يتطلب تنفيذًا صحيحًا لطلبات HTTP. في نظام C# (.NET)، الأداة الرئيسية لهذه المهمة هي الفئة HttpClient. ومع ذلك، يرتكب العديد من المطورين، خاصة المبتدئين، أخطاء نموذجية: إنشاء مثيل جديد من HttpClient لكل طلب، نسيان معالجة الاستثناءات، أو العمل بشكل غير صحيح مع البرمجة غير المتزامنة.
في هذه المقالة، سنشرح كيفية تنظيم عميل HTTP بشكل صحيح في C#، وسننظر في إرسال طلبات GET و POST، والعمل مع الرؤوس ونص الطلب، بالإضافة إلى أفضل الممارسات لمعالجة الأخطاء. بعد القراءة، ستتمكن من كتابة كود موثوق وفعال للتفاعل مع أي REST API.
أساسيات العمل مع HttpClient في C#
الفئة HttpClient موجودة في مساحة الأسماء System.Net.Http ومتاحة في جميع الإصدارات الحديثة من .NET (Core، 5، 6، 7، 8 وما فوق). ميزتها الرئيسية هي دعم العمليات غير المتزامنة والإدارة التلقائية لمجموعة الاتصالات.
إنشاء HttpClient بشكل صحيح
القاعدة الأهم: لا تنشئ HttpClient جديدًا لكل طلب. هذا قد يؤدي إلى استنفاد المقابس (socket exhaustion). بدلاً من ذلك، استخدم مثيلًا واحدًا طوال عمر التطبيق أو استخدم IHttpClientFactory.
// ❌ سيء: HttpClient جديد لكل طلب
using (var client = new HttpClient())
{
var response = await client.GetAsync("https://api.example.com");
}
// ✅ جيد: HttpClient واحد لجميع الطلبات
public class MyHttpService
{
private static readonly HttpClient _client = new HttpClient();
public async Task<string> GetDataAsync(string url)
{
return await _client.GetStringAsync(url);
}
}
الإعدادات الأساسية
عند تهيئة HttpClient، يمكنك تعيين العنوان الأساسي، المهلات، والرؤوس الافتراضية:
public class ApiClient
{
private readonly HttpClient _httpClient;
public ApiClient()
{
_httpClient = new HttpClient
{
BaseAddress = new Uri("https://api.pythonlib.ru/"),
Timeout = TimeSpan.FromSeconds(10)
};
// الرؤوس التي سيتم إرسالها مع كل طلب
_httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
_httpClient.DefaultRequestHeaders.Add("User-Agent", "MyApp/1.0");
}
}
إرسال طلبات GET و POST
سننظر في أكثر نوعين شيوعًا من طلبات HTTP: الحصول على البيانات (GET) وإرسال البيانات (POST).
طلب GET: الحصول على البيانات
يستخدم طلب GET لقراءة البيانات من الخادم. لا يجب أن يغير حالة المورد ولا يحتوي على نص.
public async Task<string> GetUserAsync(int userId)
{
try
{
var response = await _httpClient.GetAsync($"/api/users/{userId}");
response.EnsureSuccessStatusCode(); // سيرمي استثناء عند الخطأ
return await response.Content.ReadAsStringAsync();
}
catch (HttpRequestException ex)
{
Console.WriteLine($"خطأ في الطلب: {ex.Message}");
throw;
}
}
للحالات البسيطة، يمكن استخدام الصيغة المختصرة:
string json = await _httpClient.GetStringAsync("/api/users/42");
طلب POST: إرسال البيانات
يستخدم طلب POST لإنشاء موارد جديدة. يتم إرسال البيانات في نص الطلب، غالبًا بتنسيق JSON.
public async Task<User> CreateUserAsync(User newUser)
{
// تسلسل الكائن إلى JSON
var json = JsonSerializer.Serialize(newUser);