C# GET/POST request
last modified October 16, 2026
In this article we show how to send HTTP GET and POST requests in C# with
HttpClient.
HTTP
The Hypertext Transfer Protocol (HTTP) is an application protocol for distributed, collaborative, hypermedia information systems. HTTP is the foundation of data communication for the World Wide Web.
The HTTP GET method requests a representation of the specified resource. Requests using GET should only retrieve data. Parameters are sent in the query string of the URL.
The HTTP POST method sends data to the server in the body of the request. It is often used when submitting a web form or when creating a resource in a REST API.
In the examples, we use httpbin.org, a freely available HTTP
request and response service, which returns the details of our requests in
JSON, and example.com, a small page reserved for documentation
examples.
WebRequest,
HttpWebRequest, and WebClient classes. They are
obsolete since .NET 6 and the compiler reports the SYSLIB0014 warning for them.
New code should use HttpClient.
C# GET request
The GetStringAsync method sends a GET request and returns the
body of the response as a string.
using var client = new HttpClient();
string content = await client.GetStringAsync("https://example.com");
Console.WriteLine(content);
The program fetches the contents of a small web page and prints the HTML code to the console.
$ dotnet run
<!doctype html><html lang=en><head><meta charset=utf-8><link rel=icon href=data:,><meta name=viewport content="width=device-width,initial-scale=1"><title>Example Domain</title><style>html{color-scheme:light dark;background:light-dark(#eee,#222)}body{font:16px/1.6 system-ui,sans-serif;max-width:26em;margin:auto;padding:25vh 2em 2em;text-align:center}</style></head><body><p>This domain is for use in documentation examples without needing permission. This is not a service; avoid relying on it for testing and monitoring purposes.</p><script src=/s.js></script></body></html>
In our examples, we create a client for a single request. In a real
application, an HttpClient instance should be created once and
reused for many requests, because each instance holds its own pool of
connections. In ASP.NET Core and other applications with dependency injection,
we would use IHttpClientFactory.
C# response status code
The GetAsync method returns an HttpResponseMessage,
which gives access to the status code, the headers, and the body of the
response.
using var client = new HttpClient();
using var response = await client.GetAsync("https://httpbin.org/status/404");
Console.WriteLine((int) response.StatusCode);
Console.WriteLine(response.StatusCode);
Console.WriteLine(response.IsSuccessStatusCode);
try
{
response.EnsureSuccessStatusCode();
}
catch (HttpRequestException e)
{
Console.WriteLine(e.Message);
}
We request a resource that returns the 404 Not Found status.
Console.WriteLine(response.IsSuccessStatusCode);
The IsSuccessStatusCode property is true for status codes in the
range 200-299.
response.EnsureSuccessStatusCode();
The EnsureSuccessStatusCode method throws an
HttpRequestException if the request was not successful. Note that
GetAsync itself does not throw for error status codes, while
GetStringAsync does.
$ dotnet run 404 NotFound False Response status code does not indicate success: 404 (NOT FOUND).
C# GET request with query parameters
Query parameters are appended to the URL. Their values must be encoded,
because characters such as spaces or & have a special meaning
in a URL.
using System.Net.Http.Json;
using var client = new HttpClient();
var name = "John Doe";
var occupation = "gardener & florist";
var url = $"https://httpbin.org/get?name={Uri.EscapeDataString(name)}" +
$"&occupation={Uri.EscapeDataString(occupation)}";
Console.WriteLine(url);
var res = await client.GetFromJsonAsync<HttpBinResponse>(url);
foreach (var (key, value) in res!.Args)
{
Console.WriteLine($"{key}: {value}");
}
record HttpBinResponse(Dictionary<string, string> Args);
We send two query parameters. The httpbin service returns them in the
args field of its JSON response.
var url = $"https://httpbin.org/get?name={Uri.EscapeDataString(name)}" +
$"&occupation={Uri.EscapeDataString(occupation)}";
The Uri.EscapeDataString method encodes the values.
var res = await client.GetFromJsonAsync<HttpBinResponse>(url);
The GetFromJsonAsync extension method from the
System.Net.Http.Json namespace sends a GET request and deserializes
the JSON response into the given type. The property names are matched
case-insensitively.
$ dotnet run https://httpbin.org/get?name=John%20Doe&occupation=gardener%20%26%20florist name: John Doe occupation: gardener & florist
C# POST request with JSON data
The PostAsJsonAsync extension method serializes an object to JSON
and sends it in the body of a POST request.
using System.Net.Http.Json;
using var client = new HttpClient();
var user = new User("John Doe", "gardener");
using var response = await client.PostAsJsonAsync("https://httpbin.org/post", user);
response.EnsureSuccessStatusCode();
var res = await response.Content.ReadFromJsonAsync<HttpBinResponse>();
Console.WriteLine(res!.Headers["Content-Type"]);
Console.WriteLine(res.Data);
Console.WriteLine(res.Json);
record User(string Name, string Occupation);
record HttpBinResponse(string Data, User Json, Dictionary<string, string> Headers);
We send a user object. The httpbin service echoes the request: the
data field contains the raw body and the json field
the parsed JSON.
using var response = await client.PostAsJsonAsync("https://httpbin.org/post", user);
The object is serialized with System.Text.Json using the web
defaults; therefore, the property names are in camel case. The
Content-Type header is set to application/json.
var res = await response.Content.ReadFromJsonAsync<HttpBinResponse>();
We read the response body and deserialize it with
ReadFromJsonAsync.
$ dotnet run
application/json; charset=utf-8
{"name":"John Doe","occupation":"gardener"}
User { Name = John Doe, Occupation = gardener }
C# POST request with StringContent
If we already have the JSON as a string, we send it with
StringContent.
using System.Text;
using System.Text.Json;
using var client = new HttpClient();
var json = """{"name": "John Doe", "occupation": "gardener"}""";
using var content = new StringContent(json, Encoding.UTF8, "application/json");
using var response = await client.PostAsync("https://httpbin.org/post", content);
string body = await response.Content.ReadAsStringAsync();
using var doc = JsonDocument.Parse(body);
var sent = doc.RootElement.GetProperty("json");
Console.WriteLine(sent.GetProperty("name").GetString());
Console.WriteLine(sent.GetProperty("occupation").GetString());
The JSON data is written as a raw string literal. The StringContent
constructor takes the text, the encoding, and the media type. We read the
response as a string and parse it with JsonDocument.
$ dotnet run John Doe gardener
C# POST request with form data
HTML forms send their data encoded as
application/x-www-form-urlencoded. The
FormUrlEncodedContent class creates such content from name/value
pairs.
using System.Net.Http.Json;
using var client = new HttpClient();
var values = new Dictionary<string, string>
{
["name"] = "John Doe",
["occupation"] = "gardener"
};
using var data = new FormUrlEncodedContent(values);
using var response = await client.PostAsync("https://httpbin.org/post", data);
var res = await response.Content.ReadFromJsonAsync<HttpBinResponse>();
Console.WriteLine(res!.Headers["Content-Type"]);
foreach (var (key, value) in res.Form)
{
Console.WriteLine($"{key}: {value}");
}
record HttpBinResponse(Dictionary<string, string> Form, Dictionary<string, string> Headers);
The data is stored in a dictionary. The httpbin service returns the parsed form
fields in the form field of the response.
$ dotnet run application/x-www-form-urlencoded name: John Doe occupation: gardener
C# client configuration and headers
A client can be configured with a base address, a timeout, and default headers that are sent with every request.
using System.Net.Http.Json;
using var client = new HttpClient
{
BaseAddress = new Uri("https://httpbin.org/"),
Timeout = TimeSpan.FromSeconds(10)
};
client.DefaultRequestHeaders.UserAgent.ParseAdd("ZetCodeApp/1.0");
client.DefaultRequestHeaders.Accept.ParseAdd("application/json");
var res = await client.GetFromJsonAsync<HttpBinResponse>("headers");
Console.WriteLine(res!.Headers["User-Agent"]);
Console.WriteLine(res.Headers["Accept"]);
record HttpBinResponse(Dictionary<string, string> Headers);
The /headers endpoint of httpbin returns the headers it received.
BaseAddress = new Uri("https://httpbin.org/"),
Relative URLs, such as headers, are resolved against the base
address. The base address should end with a slash.
client.DefaultRequestHeaders.UserAgent.ParseAdd("ZetCodeApp/1.0");
By default, HttpClient sends no User-Agent header.
Some servers reject such requests, so it is a good practice to set it.
$ dotnet run ZetCodeApp/1.0 application/json
Source
Make HTTP requests with the HttpClient class
In this article we have shown how to send GET and POST requests in C#.
Author
List all C# tutorials.