How to Send an HTTP POST Request in .NET in C#: From Simple to Complex
\n\nImagine your C# application is a courier that needs to deliver a package (data) to a specific address (URL) and receive confirmation (response). This is exactly the task that an HTTP POST request solves. On Stack Overflow, this question gathers thousands of views, and for good reason: working with external APIs, sending forms, uploading data to a server — this is the daily routine of any .NET developer.
\n\nIn this article, we will cover three main ways to send a POST request in .NET (C#), starting with the modern HttpClient and ending with the "legacy" WebRequest. You will learn how to transmit JSON, URL-encoded data, handle errors, and avoid pitfalls that await beginners. Let's go!
1. Modern Approach: HttpClient (Recommended)
\n\nStarting with .NET Framework 4.5 and in all versions of .NET Core / .NET 5+, the HttpClient class is the de facto standard. It is designed for asynchronous work, supports connection reuse, and is easily configurable.
1.1. Simple POST with JSON (Most Common Scenario)
\n\nLet's say we need to send user data to the server in JSON format. Here's what it looks like in real code:
\n\nusing System;\nusing System.Net.Http;\nusing System.Text;\nusing System.Text.Json;\nusing System.Threading.Tasks;\n\npublic class UserService\n{\n private readonly HttpClient _httpClient;\n\n public UserService(HttpClient httpClient)\n {\n _httpClient = httpClient;\n }\n\n public async Task<UserResponse> CreateUserAsync(UserDto newUser)\n {\n // 1. Serialize the object to JSON\n var json = JsonSerializer.Serialize(newUser);\n var content = new StringContent(json, Encoding.UTF8, "application/json");\n\n // 2. Send POST\n HttpResponseMessage response = await _httpClient.PostAsync("https://api.example.com/users", content);\n\n // 3. Read the response\n response.EnsureSuccessStatusCode(); // Will throw an exception if status is not 2xx\n\n var responseBody = await response.Content.ReadAsStringAsync();\n return JsonSerializer.Deserialize<UserResponse>(responseBody);\n }\n}\n\n// Usage example\npublic class Program\n{\n public static async Task Main()\n {\n var client = new HttpClient();\n var service = new UserService(client);\n \n var user = new UserDto { Name = "Ivan", Email = "ivan@example.com" };\n var result = await service.CreateUserAsync(user);\n Console.WriteLine($"Created user ID: {result.Id}");\n }\n}\n\npublic class UserDto\n{\n public string Name { get; set; }\n public string Email { get; set; }\n}\n\npublic class UserResponse\n{\n public int Id { get; set; }\n}\n\nImportant points:
\n- \n
- Always use
async/await— this prevents the thread from blocking. \n EnsureSuccessStatusCode()— your best friend for quick error checking. \n - Do not create a new
HttpClientfor each request — this leads to socket exhaustion. UseIHttpClientFactoryin ASP.NET Core or a single static instance. \n
1.2. POST with Form Data (application/x-www-form-urlencoded)
\n\nSometimes the API requires data in the format of a regular HTML form. For this, we use FormUrlEncodedContent:
public async Task<string> PostFormDataAsync(string username, string password)\n{\n var formData = new Dictionary<string, string>\n {\n { "grant_type", "password" },\n { "username", username },\n { "password", password }\n };\n\n var content = new FormUrlEncodedContent(formData);\n\n using var client = new HttpClient();\n var response = awa