RestWrapper 3.2.0
dotnet add package RestWrapper --version 3.2.0
NuGet\Install-Package RestWrapper -Version 3.2.0
<PackageReference Include="RestWrapper" Version="3.2.0" />
<PackageVersion Include="RestWrapper" Version="3.2.0" />
<PackageReference Include="RestWrapper" />
paket add RestWrapper --version 3.2.0
#r "nuget: RestWrapper, 3.2.0"
#:package RestWrapper@3.2.0
#addin nuget:?package=RestWrapper&version=3.2.0
#tool nuget:?package=RestWrapper&version=3.2.0
RestWrapper
RestWrapper is a small C# library for sending HTTP requests without rebuilding the same request, header, authorization, streaming, and response-handling code in every project.
It wraps HttpClient with a compact API for:
- standard REST verbs
- custom headers and content types
- basic, bearer, and raw authorization headers
- JSON serialization/deserialization
- response timing metadata
- server-sent events
- chunked request and response workflows
- optional caller-supplied
HttpClientinstances
Why RestWrapper
If you want something lighter than a full API client framework but more structured than hand-rolled HttpClient calls, RestWrapper sits in the middle:
- request setup is explicit and easy to read
- response access is simple for text, bytes, streams, JSON, SSE, and chunked flows
- you can keep using your own
HttpClientfor DI, proxies, mTLS, custom handlers, and connection reuse - the library stays close to the underlying HTTP model instead of inventing a large abstraction layer
Target Frameworks
RestWrapper currently targets:
netstandard2.0netstandard2.1net462net48net6.0net8.0net10.0
Install
dotnet add package RestWrapper
Quick Start
Simple GET:
using RestWrapper;
using RestRequest request = new RestRequest("https://api.example.com/status");
using RestResponse response = await request.SendAsync();
Console.WriteLine(response.StatusCode);
Console.WriteLine(response.DataAsString);
Simple POST:
using RestWrapper;
using System.Net.Http;
using RestRequest request = new RestRequest("https://api.example.com/messages", HttpMethod.Post);
request.ContentType = "text/plain";
using RestResponse response = await request.SendAsync("Hello, world!");
Console.WriteLine(response.StatusCode);
Console.WriteLine(response.DataAsString);
JSON response handling:
using RestWrapper;
using RestRequest request = new RestRequest("https://api.example.com/items/123");
using RestResponse response = await request.SendAsync();
MyDto dto = response.DataFromJson<MyDto>();
Console.WriteLine(dto.Name);
Form data:
using RestWrapper;
using System.Net.Http;
using RestRequest request = new RestRequest("https://api.example.com/login", HttpMethod.Post);
Dictionary<string, string> form = new Dictionary<string, string>
{
{ "username", "alice" },
{ "password", "secret" }
};
using RestResponse response = await request.SendAsync(form);
Console.WriteLine(response.StatusCode);
Request Configuration
Headers and content type
using RestWrapper;
using System.Net.Http;
using RestRequest request = new RestRequest("https://api.example.com/items", HttpMethod.Post);
request.ContentType = "application/json; charset=utf-8";
request.Headers.Add("X-Correlation-Id", Guid.NewGuid().ToString());
request.Headers.Add("X-Tenant", "east");
using RestResponse response = await request.SendAsync("{\"name\":\"demo\"}");
Authorization
Basic auth:
using RestWrapper;
using RestRequest request = new RestRequest("https://api.example.com/secure");
request.Authorization.User = "alice";
request.Authorization.Password = "secret";
using RestResponse response = await request.SendAsync();
Bearer auth:
using RestWrapper;
using RestRequest request = new RestRequest("https://api.example.com/secure");
request.Authorization.BearerToken = "your-token";
using RestResponse response = await request.SendAsync();
Raw authorization header:
using RestWrapper;
using RestRequest request = new RestRequest("https://api.example.com/secure");
request.Authorization.Raw = "Custom scheme-value";
using RestResponse response = await request.SendAsync();
Streams
using RestWrapper;
using System.Net.Http;
using System.Text;
byte[] payload = Encoding.UTF8.GetBytes("streamed payload");
using MemoryStream stream = new MemoryStream(payload);
using RestRequest request = new RestRequest("https://api.example.com/upload", HttpMethod.Put);
request.ContentType = "text/plain";
using RestResponse response = await request.SendAsync(payload.Length, stream);
Console.WriteLine(response.StatusCode);
Response Handling
For regular responses, RestWrapper gives you multiple access patterns:
response.Datafor the raw streamresponse.DataAsBytesfor the buffered byte arrayresponse.DataAsStringfor UTF-8 string contentresponse.DataFromJson<T>()for JSON payloads
Example:
using RestWrapper;
using RestRequest request = new RestRequest("https://api.example.com/items/123");
using RestResponse response = await request.SendAsync();
Console.WriteLine(response.IsSuccessStatusCode);
Console.WriteLine(response.ContentType);
Console.WriteLine(response.ContentLength);
Console.WriteLine(response.DataAsString);
Timing metadata
Each RestResponse includes a Time property:
using RestWrapper;
using RestRequest request = new RestRequest("https://api.example.com/status");
using RestResponse response = await request.SendAsync();
Console.WriteLine("Start : " + response.Time.Start);
Console.WriteLine("End : " + response.Time.End);
Console.WriteLine("Total ms : " + response.Time.TotalMs);
Server-Sent Events
When the server returns text/event-stream, use ReadEventAsync() instead of Data, DataAsString, or DataFromJson<T>().
using RestWrapper;
using RestRequest request = new RestRequest("https://api.example.com/events");
using RestResponse response = await request.SendAsync();
while (true)
{
ServerSentEvent evt = await response.ReadEventAsync();
if (evt == null) break;
Console.WriteLine($"[{evt.Event}] {evt.Data}");
}
ServerSentEvent exposes:
IdEventDataRetry
Chunked Transfer
RestWrapper supports chunked request sending and chunked response reading.
using RestWrapper;
using System.Net.Http;
using RestRequest request = new RestRequest("https://api.example.com/chunked", HttpMethod.Post);
request.ChunkedTransfer = true;
await request.SendChunkAsync("chunk-1", false);
await request.SendChunkAsync("chunk-2", false);
using RestResponse response = await request.SendChunkAsync(Array.Empty<byte>(), true);
while (true)
{
ChunkData chunk = await response.ReadChunkAsync();
if (chunk == null) break;
Console.WriteLine(System.Text.Encoding.UTF8.GetString(chunk.Data));
if (chunk.IsFinal) break;
}
As with SSE, chunked responses are a specialized mode. Use ReadChunkAsync() instead of Data, DataAsString, DataAsBytes, or DataFromJson<T>().
Caller-Supplied HttpClient
If you already manage HttpClient instances through dependency injection or need custom handler behavior, you can provide your own HttpClient to RestRequest.
using RestWrapper;
using System.Net.Http;
using HttpClient client = new HttpClient();
using RestRequest request = new RestRequest(
"https://api.example.com/resource",
HttpMethod.Get,
client);
using RestResponse response = await request.SendAsync();
Console.WriteLine(response.StatusCode);
This is useful for:
- connection reuse
- proxy settings
- mTLS and client certificates
- custom message handlers
- centralized
HttpClientFactoryusage
Important behavior:
- caller-supplied clients remain caller-owned
RestRequestwill not dispose an externalHttpClient- per-request headers and authorization are applied at the request-message level so shared clients do not leak state between requests
When you supply your own HttpClient, transport-level settings also become caller-owned. In that mode, do not use these RestRequest properties:
TimeoutMillisecondsAllowAutoRedirectIgnoreCertificateErrorsCertificateFilenameCertificatePassword
Configure those on your HttpClient / handler instead.
Custom Serialization
RestResponse.DataFromJson<T>() uses System.Text.Json by default, but you can replace the serializer:
using RestWrapper;
using RestRequest request = new RestRequest("https://api.example.com/items/123");
using RestResponse response = await request.SendAsync();
response.SerializationHelper = new MySerializer();
MyDto dto = response.DataFromJson<MyDto>();
MySerializer just needs to implement ISerializationHelper.
Test Projects
The repository includes both interactive and automated test hosts:
src/Testis the interactive console appsrc/Test.Sharedcontains the shared Touchstone suitessrc/Test.Automatedis the console/CLI automation runnersrc/Test.Xunitexposes the shared suite throughdotnet testsrc/Test.Nunitexposes the same shared suite throughdotnet test
The current automated surface contains 120 shared cases covering:
- internal and caller-supplied
HttpClientflows - positive and negative transport behavior
- shared-client header/auth isolation
- SSE parsing, cancellation, and misuse guards
- chunked read behavior, cancellation, and framing
- response guards for regular vs streaming modes
- serializer and helper utilities
Localhost Note
RestWrapper uses the platform HttpClient stack. When targeting localhost, some environments will try IPv6 loopback first. If your local service is only listening on IPv4, that can introduce a noticeable delay.
If you see this behavior, prefer 127.0.0.1 instead of localhost.
Changelog
See CHANGELOG.md for version history.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 is compatible. |
| .NET Framework | net461 was computed. net462 is compatible. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 is compatible. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETFramework 4.6.2
- System.Net.Http (>= 4.3.4)
- System.Text.Json (>= 8.0.6)
- Timestamps (>= 1.0.11)
-
.NETFramework 4.8
- System.Net.Http (>= 4.3.4)
- System.Text.Json (>= 8.0.6)
- Timestamps (>= 1.0.11)
-
.NETStandard 2.0
- System.Text.Json (>= 8.0.6)
- Timestamps (>= 1.0.11)
-
.NETStandard 2.1
- System.Text.Json (>= 8.0.6)
- Timestamps (>= 1.0.11)
-
net10.0
- Timestamps (>= 1.0.11)
-
net6.0
- System.Text.Json (>= 8.0.6)
- Timestamps (>= 1.0.11)
-
net8.0
- Timestamps (>= 1.0.11)
NuGet packages (27)
Showing the top 5 NuGet packages that depend on RestWrapper:
| Package | Downloads |
|---|---|
|
KvpbaseSDK
C# SDK for Kvpbase object storage platform |
|
|
Komodo.Sdk
Client SDK in C# for Komodo. Please either install Komodo.Daemon to integrate search within your application, or Komodo.Server to run a standalone server if you wish to use this client SDK. Komodo is an information search, metadata, storage, and retrieval platform. |
|
|
GoogleMapsClient
I needed a simple way to parse addresses and resolve coordinates to an address. Plug in a Google Maps API key and you're all set. |
|
|
LiteGraph
LiteGraph is a property graph database with support for graph relationships, tags, labels, metadata, data, and vectors. |
|
|
SendWithBrevo
A simple C# class library to help simplify sending emails using Brevo. |
GitHub repositories (2)
Showing the top 2 popular GitHub repositories that depend on RestWrapper:
| Repository | Stars |
|---|---|
|
dotnet/WatsonWebserver
Watson is the fastest, easiest way to build scalable RESTful web servers and services in C#.
|
|
|
litegraphdb/litegraph
Lightweight graph database with relational, vector, and MCP support, designed to power knowledge and artificial intelligence persistence and retrieval.
|
| Version | Downloads | Last Updated |
|---|---|---|
| 3.2.0 | 149 | 5/18/2026 |
| 3.1.8 | 8,661 | 10/4/2025 |
| 3.1.7 | 387 | 10/1/2025 |
| 3.1.6 | 778 | 9/19/2025 |
| 3.1.5 | 6,144 | 3/10/2025 |
| 3.1.4 | 6,294 | 1/22/2025 |
| 3.1.3 | 651 | 12/13/2024 |
| 3.1.2 | 5,648 | 12/10/2024 |
| 3.1.1 | 336 | 12/10/2024 |
| 3.1.0 | 757 | 12/2/2024 |
| 3.0.22 | 1,297 | 10/29/2024 |
| 3.0.21 | 4,694 | 8/27/2024 |
| 3.0.20 | 4,552 | 5/21/2024 |
| 3.0.19 | 4,292 | 3/27/2024 |
| 3.0.18 | 1,663 | 1/16/2024 |
| 3.0.17 | 6,104 | 11/25/2023 |
| 3.0.16 | 689 | 11/10/2023 |
| 3.0.15 | 656 | 11/10/2023 |
| 3.0.14 | 1,493 | 10/21/2023 |
Custom HttpClient injection support, safer shared-client request handling, and expanded automated test coverage.