C# HttpClient
Inject a deterministic handler and check the response status before reading its result.
How it works
HttpClient sends requests through a message handler, which can be supplied for a controlled test. This lesson uses an in-memory fixture handler rather than a network connection, making the response deterministic and avoiding credentials or external side effects. Production clients need timeouts, cancellation, response-size limits and a policy for retrying only appropriate failures. Reuse clients according to their lifetime contract; creating one per real request can create connection-management problems.
Run it locally
Use the .NET 10 SDK with C# 14 in a separate console lab. Create an empty project once with dotnet new console --framework net10.0, then replace Program.cs with this complete source and add any supporting files shown. Keep only one lesson entry point in the project. C# does not currently run in Bhylu’s browser playground. Apache, PHP and MySQL are not needed.
dotnet build -p:LangVersion=14.0 -p:Nullable=enable -p:TreatWarningsAsErrors=true
dotnet run --no-buildUse the SDK’s project workflow; the review compiles against its matching reference assemblies and executes the results without external NuGet packages. File-writing examples belong in a private empty lab directory.
Environment boundary: In-memory HttpMessageHandler fixture only. No live request, loopback server, TLS verification or external API delivery is claimed.
Example
using System;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
internal static class Program
{
private static async System.Threading.Tasks.Task Main(string[] args)
{
using var client = new HttpClient(new FixtureHandler());
using HttpResponseMessage response = await client.GetAsync("https://fixture.invalid/workshops");
response.EnsureSuccessStatusCode();
string body = await response.Content.ReadAsStringAsync();
Console.WriteLine(body);
}
}
internal sealed class FixtureHandler : HttpMessageHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken token)
{
token.ThrowIfCancellationRequested();
if (request.RequestUri?.AbsolutePath != "/workshops")
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.NotFound));
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent("2 workshops available") });
}
}
Expected result
2 workshops available
The supplied handler returns an owned response entirely in memory. The example tests client-side handler composition and status handling, not DNS, TLS, sockets or a live API. The reserved invalid hostname is never contacted. A production import must still validate the response’s content and domain schema instead of treating HTTP 200 as proof of a valid booking.
Consult Microsoft’s C# documentation for language and library contracts, including target-framework and version requirements.